title: Using a Java Stream instead of a for-loop skips code execution
body: <p>Switching a bunch of for-loop code to use a parallel stream is apparently causing a certain part of the code to be ignored.</p>
  
  <p>I'm using MOA and Weka with Java 11 to run a simple recommendation engine example, taking cues from the source code of <code>moa.tasks.EvaluateOnlineRecomender</code>, which uses MOA's internal task setup to test the accuracy of the Biased Regularized Incremental Simultaneous Matrix Factorization (BRISMF) implementation provided by MOA. Instead of using MOA's prepared <code>MovielensDataset</code> class, I switched over to Weka's <code>Instances</code> for prospects of applying Weka's ML tools.</p>
  
  <p>The time it took to process about a million instances (I'm using the Movielens 1M dataset) was about 13-14 minutes. In a bid to see improvements, I wanted to run it on a parallel stream, and became suspicious when the task finished in about 40 seconds. I found that <code>BRISMFPredictor.predictRating</code> was always producing 0 within the parallel stream's body. Here's the code for either case:</p>
  
  <p>Code for initialisation:</p>
  
  <pre><code>import com.github.javacliparser.FileOption;
  import com.github.javacliparser.IntOption;
  
  import moa.options.ClassOption;
  import moa.recommender.predictor.BRISMFPredictor;
  import moa.recommender.predictor.RatingPredictor;
  import moa.recommender.rc.data.RecommenderData;
  import weka.core.converters.CSVLoader;
  </code></pre>
  
  <p>...</p>
  
  <pre><code>private static ClassOption datasetOption;
  private static ClassOption ratingPredictorOption;
  private static IntOption sampleFrequencyOption;
  private static FileOption defaultFileOption;
  
  static {
      ratingPredictorOption = new ClassOption("ratingPredictor",
              's', "Rating Predictor to evaluate on.", RatingPredictor.class,
              "moa.recommender.predictor.BRISMFPredictor");
      sampleFrequencyOption = new IntOption("sampleFrequency",
              'f', "How many instances between samples of the learning performance.", 100, 0, 2147483647);
      defaultFileOption = new FileOption("file",
              'f', "File to load.",
              "C:\\Users\\shiva\\Documents\\Java-ML\\mlapp\\data\\ml-1m\\ratings.dat", "dat", false);
  }
  </code></pre>
  
  <p>... and inside <code>main()</code> (a quirk with Weka's <code>CSVLoader</code> required that I replace the default <code>::</code> delimiter with <code>+</code>)</p>
  
  <pre><code>    var csvLoader = new CSVLoader();
      csvLoader.setSource(defaultFileOption.getFile());
      csvLoader.setFieldSeparator("+");
      var dataset = csvLoader.getDataSet();
      System.out.println(dataset.toSummaryString());
  
      var predictor = new BRISMFPredictor();
      predictor.prepareForUse();
  
      RecommenderData data = predictor.getData();
      data.clear();
      data.disableUpdates(false);
  </code></pre>
  
  <p>Now, alternating between the following snippets:</p>
  
  <pre><code>for (var instance : dataset) {
      var user = (int) instance.value(0);
      var item = (int) instance.value(1);
      var rating = instance.value(2);
  
      double predictedRating = predictor.predictRating(user, item);
  
      System.out.printf("User %d | Movie %d | Actual Rating %d | Predicted Rating %f%n",
                      user, item, Math.round(rating), predictedRating);
  }
  </code></pre>
  
  <p>(Now being a noob in everything concurrent):</p>
  
  <pre><code>dataset.parallelStream().forEach(instance -&gt; {
      var user = (int) instance.value(0);
      var item = (int) instance.value(1);
      var rating = instance.value(2);
  
      double predictedRating = predictor.predictRating(user, item);
  
      System.out.printf("User %d | Movie %d | Actual Rating %d | Predicted Rating %f%n",
                      user, item, Math.round(rating), predictedRating);
  });
  </code></pre>
  
  <p>Now I decide that heck, maybe this operation can't be done in parallel, and I switch it to use <code>stream()</code>. Even then, the segment seems to be completely ignored since the output is again 0.0 each time</p>
  
  <pre><code>dataset.stream().forEach(instance -&gt; {
      var user = (int) instance.value(0);
      var item = (int) instance.value(1);
      var rating = instance.value(2);
  
      double predictedRating = predictor.predictRating(user, item);
  
      System.out.printf("User %d | Movie %d | Actual Rating %d | Predicted Rating %f%n",
                      user, item, Math.round(rating), predictedRating);
  });
  </code></pre>
  
  <p>I have tried removing the print statement from the run, but without avail.</p>
  
  <p>Obviously, I get the expected output lines consisting of actual and predicted rating within about 13 minutes in the first case, but find that the predicted rating is 0.0 in the second case with suspiciously low execution time. Is there something I'm missing out on?</p>
  
  <p>EDIT: using <code>dataset.forEach()</code> does the same thing. Perhaps a quirk of lambdas?</p>