0

I was working with some Java 8 Stream APIs. I am confused to see the performance difference between below two solutions, that are just printing the contents of Stream.

Solution 1:

int[] array = new int[] { 0, 1, 2, 3, 4, 5 };
start = System.nanoTime();
Arrays.stream(array).forEach(System.out::println);
System.out.println((System.nanoTime() - start) / 1000000.0f);

Solution 2:

int[] array = new int[] { 0, 1, 2, 3, 4, 5 };
start = System.nanoTime();
Arrays.stream(array).forEach(new IntConsumer() {
    @Override
    public void accept(int value) {
        System.out.println(value);
    }
});
System.out.println((System.nanoTime() - start) / 1000000.0f);

For execution, Solution 1 is taking approx. 5-6 times more time than Solution 2.

System Configuration:

  • JRE: 1.8.0_101 64 bit
  • OS: Windows 10 Home 64-bit
  • RAM: 4 GB
  • IDE: Eclipse Mas-1 for Java EE 64-bit

It would be helpful if someone can explain, Why there is this huge difference?

JMH Code:

public class MyBenchmark {

    @Benchmark
    public void solution_0() {
        int[] array = new int[] { 0, 1, 2, 3, 4, 5 };
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);asdasdas
        }
    }

    @Benchmark
    public void solution_1() {
        int[] array = new int[] { 0, 1, 2, 3, 4, 5 };
        Arrays.stream(array).forEach(new IntConsumer() {
            @Override
            public void accept(int value) {
                System.out.println(value);
            }
        });
    }

    @Benchmark
    public void solution_2() {
        int[] array = new int[] { 0, 1, 2, 3, 4, 5 };
        Arrays.stream(array).forEach(System.out::println);
    }
}
Amber Beriwal
  • 1,568
  • 16
  • 30
  • 2
    How are you measuring? Are you using just one run? Micro-benchmarks are not easy stuff. You need to warm-up, discard highest and lowest values, take average and standard deviation into account, etc – fps Oct 09 '16 at 21:41
  • 2
    You should try to learn something about Java microbenchmarks before saying which method is faster. Search for Jmh – Sergio Otero Lopez Oct 09 '16 at 21:42
  • @FedericoPeraltaSchaffner I have taken it on account of 100 iterations and skipped first few elements as they were having significant change. I have run the same program 4-5 times and every-time results were same. – Amber Beriwal Oct 10 '16 at 05:14
  • @SergioOteroLopez I tried JMH with Mode.All, but I get results only in `ns/op` and `ops/ns`. Ideally, both should be same for both algorithms. I couldn't find anything to get absolute average time. – Amber Beriwal Oct 10 '16 at 05:16

1 Answers1

9

You are measuring the instantiation of method reference, not its runtime performance.

On the first use of method reference (System.out::println) JVM needs to create an internal class which implements IntConsumer interface. Of course, this takes time. Though this is done only once during application lifetime.

In the second case you've made such anonymous class yourself.

If you wish to measure the runtime performance of method references, you have to revise the benchmarking metodology. See "How do I write a correct micro-benchmark in Java?"

Community
  • 1
  • 1
apangin
  • 92,924
  • 10
  • 193
  • 247
  • Hi..I tried JMH with Mode.All, but I get results only in `ns/op` and `ops/ns`. Ideally, both should be same for both algorithms. I couldn't find anything to get absolute average time. Any idea would be helpful on how can I check average time. – Amber Beriwal Oct 10 '16 at 05:17
  • @AmberBeriwal Isn't `ns/op` the average time you are looking for? – apangin Oct 10 '16 at 07:49
  • I understand it as nanoseconds/operation, please correct me if I am wrong. So as per my understanding, if code 1 contains 100 operations and completed in 1000 ns then it would be 10 ns/op. Now, if code 2 contains 200 operations and completed in 2000 ms then that would also be 10 ns/op. But, in actual code 2 is taking 2000 ms. – Amber Beriwal Oct 10 '16 at 09:07
  • @AmberBeriwal *"operation"* - is what inside `@Benchmark` method. You should basically put the code you'd like to measure inside a single @Benchmark-annotated method. Please update the question with the JMH code you've come up with. – apangin Oct 10 '16 at 09:30
  • @AmberBeriwal I've done a benchmark for lambda vs anonymous class for a different question, you can compare yours with it [here is the link](http://stackoverflow.com/a/39723040/2176572) – bashnesnos Oct 10 '16 at 10:01
  • @bashnesnos does it mean, it does not affect performance whether use lambda expression or anonymous class? – Amber Beriwal Oct 10 '16 at 16:08
  • @AmberBeriwal if you disregard initialization (as apangin explained in his answer), the runtime performance is pretty much the same – bashnesnos Oct 11 '16 at 08:11
  • @bashnesnos ok..I will just go through some rounds of verification before acceptance of answer. I didn't knew, one method invocation is called one operation. Thanks for this clarification. – Amber Beriwal Oct 11 '16 at 08:20