Why is my java lambda with a dummy assignment much faster than without it? : <p>I know that making judgements of Java microbenchmarks is extremely fraught, but I'm seeing something that seems odd, and I'd like to get some explanation for it.</p>

<p>Note that I'm not using the <a href="http://openjdk.java.net/projects/code-tools/jmh/" title="JMH">JMH</a> framework for this.  I'm aware of it, but I didn't want to go to that length for this.</p>

<p>I'll provide the entire code sample, but in short, when I test the performance of these two methods</p>

<pre><code>private FooPrime[] testStreamToArray(ArrayList&lt;Foo&gt; fooList) {
    return (FooPrime[]) fooList.stream().
                map(it -&gt; {
                    return new FooPrime().gamma(it.getAlpha() + it.getBeta());
                }).
                toArray(FooPrime[]::new);
}

private FooPrime[] testStreamToArray2(ArrayList&lt;Foo&gt; fooList) {
    return (FooPrime[]) fooList.stream().
                map(it -&gt; {
                    int stuff = it.getAlpha().length();
                    return new FooPrime().gamma(it.getAlpha() + it.getBeta());
                }).
                toArray(FooPrime[]::new);
}
</code></pre>

<p>I find very surprising results.  In the larger code sample, I'm measuring four different ways of doing this, and the first three are very close in performance.  They all run about 50k ns per iteration.  However, the second code sample consistently runs just under half of that total.  That's right.  It's not slower, it's quite a bit faster.</p>

<p>The last run shows numbers like this:</p>

<pre><code>manualcopy:54575 ns
toarray:53617 ns
streamtoarray:52990 ns
streamtoarray2:24217 ns
</code></pre>

<p>Each run has numbers similar to these.</p>

<p>I'll now provide the entire class and base class.  Note that I do have a "warm-up" pass, where I execute the methods under test a few thousand times before starting the timings.  Also note that although this runs "testStreamToArray2" last, I also tried moving that block to the first test, and the numbers come out about the same.  The commented out lines are there to convince me that the methods are actually doing something (the timings are still about the same with those lines not commented out).</p>

<pre><code>package timings;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ListToArrayOfPrimesTiming {

    public static void main(String[] args) {
        ListToArrayOfPrimesTiming tests = new ListToArrayOfPrimesTiming(args);
        tests.go();
    }

    public ListToArrayOfPrimesTiming(String[] args) { }

    private void go() {

        final ArrayList&lt;Foo&gt; fooList    = new ArrayList&lt;&gt;();

        for (int ctr = 0; ctr &lt; 1000; ++ ctr) {
            fooList.add(new Foo().alpha("a" + ctr).beta("b" + ctr));
        }

        for (int ctr = 0; ctr &lt; 20000; ++ ctr) {
            testManualCopy(fooList);
            testToArray(fooList);
            testStreamToArray(fooList);
            testStreamToArray2(fooList);
        }

        int iters   = 100000;

//      Set&lt;Integer&gt; lengths    = new HashSet&lt;&gt;();
//      Set&lt;FooPrime&gt;   distinctFooPrimes   = new HashSet&lt;&gt;();
//      lengths.clear();
//      distinctFooPrimes.clear();

        new TimingContainer(iters, "manualcopy", new TimingTest() {
            @Override
            public void run() {
                FooPrime[] fooPrimeArray = testManualCopy(fooList);
//              lengths.add(fooPrimeArray.length);
//              distinctFooPrimes.add(fooPrimeArray[0]);
            }
        }).run();

//      System.out.println("lengths[" + lengths + "]");
//      lengths.clear();
//      System.out.println("distinctFooPrimes[" + distinctFooPrimes + "]");
//      distinctFooPrimes.clear();

        new TimingContainer(iters, "toarray", new TimingTest() {
            @Override
            public void run() {
                FooPrime[] fooPrimeArray = testManualCopy(fooList);
//              lengths.add(fooPrimeArray.length);
//              distinctFooPrimes.add(fooPrimeArray[0]);
            }
        }).run();

//      System.out.println("lengths[" + lengths + "]");
//      lengths.clear();
//      System.out.println("distinctFooPrimes[" + distinctFooPrimes + "]");
//      distinctFooPrimes.clear();

        new TimingContainer(iters, "streamtoarray", new TimingTest() {
            @Override
            public void run() {
                FooPrime[] fooPrimeArray = testStreamToArray(fooList);
//              lengths.add(fooPrimeArray.length);
//              distinctFooPrimes.add(fooPrimeArray[0]);
            }
        }).run();

//      System.out.println("lengths[" + lengths + "]");
//      lengths.clear();
//      System.out.println("distinctFooPrimes[" + distinctFooPrimes + "]");
//      distinctFooPrimes.clear();

        new TimingContainer(iters, "streamtoarray2", new TimingTest() {
            @Override
            public void run() {
                FooPrime[] fooPrimeArray = testStreamToArray2(fooList);
//              lengths.add(fooPrimeArray.length);
//              distinctFooPrimes.add(fooPrimeArray[0]);
            }
        }).run();

//      System.out.println("lengths[" + lengths + "]");
//      lengths.clear();
//      System.out.println("distinctFooPrimes[" + distinctFooPrimes + "]");
//      distinctFooPrimes.clear();
    }

    private FooPrime[] testManualCopy(ArrayList&lt;Foo&gt; fooList) {
        FooPrime[] fooPrimeArray    = new FooPrime[fooList.size()];
        int index = -1;
        for (Foo foo: fooList) {
            ++ index;
            fooPrimeArray[index]    = new FooPrime().gamma(foo.getAlpha() + foo.getBeta());
        }
        return fooPrimeArray;
    }

    private FooPrime[] testToArray(ArrayList&lt;Foo&gt; fooList) {
        List&lt;FooPrime&gt;  fooPrimeList    = new ArrayList&lt;&gt;();
        for (Foo foo: fooList) {
            fooPrimeList.add(new FooPrime().gamma(foo.getAlpha() + foo.getBeta()));
        }
        return fooPrimeList.toArray(new FooPrime[fooList.size()]);
    }

    private FooPrime[] testStreamToArray(ArrayList&lt;Foo&gt; fooList) {
        return (FooPrime[]) fooList.stream().
                    map(it -&gt; {
                        return new FooPrime().gamma(it.getAlpha() + it.getBeta());
                    }).
                    toArray(FooPrime[]::new);
    }

    private FooPrime[] testStreamToArray2(ArrayList&lt;Foo&gt; fooList) {
        return (FooPrime[]) fooList.stream().
                    map(it -&gt; {
                        int stuff = it.getAlpha().length();
                        return new FooPrime().gamma(it.getAlpha() + it.getBeta());
                    }).
                    toArray(FooPrime[]::new);
    }

    public static FooPrime fooToFooPrime(Foo foo) {
        return new FooPrime().gamma(foo.getAlpha() + foo.getBeta());
    }

    public static class Foo {
        private String alpha;
        private String beta;

        public String getAlpha() { return alpha; }
        public String getBeta() { return beta; }

        public void setAlpha(String alpha) { this.alpha = alpha; }
        public void setBeta(String beta) { this.beta = beta; }

        public Foo alpha(String alpha) { this.alpha = alpha; return this; }
        public Foo beta(String beta) { this.beta = beta; return this; }
    }

    public static class FooPrime {
        private String gamma;

        public String getGamma() { return gamma; }

        public void setGamma(String gamma) { this.gamma = gamma; }

        public FooPrime gamma(String gamma) { this.gamma = gamma; return this; }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((gamma == null) ? 0 : gamma.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            FooPrime other = (FooPrime) obj;
            if (gamma == null) {
                if (other.gamma != null)
                    return false;
            } else if (!gamma.equals(other.gamma))
                return false;
            return true;
        }

        @Override
        public String toString() {
            return "FooPrime [gamma=" + gamma + "]";
        }
    }
}
</code></pre>

<p>And the base class:</p>

<pre><code>package timings;

public class TimingContainer {
    private int         iterations;
    private String      label;
    private TimingTest  timingTest;

    public TimingContainer(int iterations, String label, TimingTest timingTest) {
        this.iterations = iterations;
        this.label      = label;
        this.timingTest = timingTest;
    }

    public void run() {
        long startTime  = System.nanoTime();
        for (int ctr = 0; ctr &lt; iterations; ++ ctr) {
            timingTest.randomize();
            timingTest.run();
        }
        long    endTime = System.nanoTime();
        long    totalns = (endTime - startTime);
        System.out.println(label + ":" + (totalns / iterations) + " ns");
    }
}
</code></pre>
