0

I am trying to benchmark two different implementations of a Java function that checks whether a number contains at least one even digit. The first implementation uses hand written loop, while the second uses a stream.

public class StreamTest {

public boolean containsEvenDigit(int n) {
    char [] digits = String.valueOf(n).toCharArray();
    for(char d : digits) {
        if(d % 2 == 0) {
            return true;
        }
    }
    return false;
}

public boolean containsEvenDigitStreams(int n) {
    return String.valueOf(n).chars().anyMatch(i -> i % 2 == 0);
}

public static void main(String[] args) {
    System.out.println("============WITHOUT STREAM============");
    long start1 = System.nanoTime();
    for(int i = 0 ; i < 1_000_000; i++) {
        (new StreamTest()).containsEvenDigit(11215 + i);
    }
    long duration1 = (long)(System.nanoTime() - start1)/1_000_000;
    System.out.println("Duration : " + duration1 + " milliseconds.");
    System.out.println();

    System.out.println("============USING STREAM============");
    long start2 = System.nanoTime();
    for(int i = 0 ; i < 1_000_000; i++) {
        (new StreamTest()).containsEvenDigitStreams(11215 + i);
    }
    long duration2 = (long)(System.nanoTime() - start2)/1_000_000;
    System.out.println("Duration : " + duration2 + " milliseconds.");
    System.out.println();

}

}

In the main function, I am not outputting the return values of the functions being tested to eliminate I/O overhead. The outcome shows that the implementation using streams performs much slower than the ones using loop.

============WITHOUT STREAM============
Duration : 119 milliseconds.

============USING STREAM============
Duration : 771 milliseconds.

Does this mean that Java 8 streams are slower than hand written loops?

Update: I am now using JMH to benchmark the two functions.

public class MyBenchmark {

private boolean containsEvenDigit(int n) {
    char [] digits = String.valueOf(n).toCharArray();
    for(char d : digits) {
        if(d % 2 == 0) {
            return true;
        }
    }
    return false;
}

private boolean containsEvenDigitStream(int n) {
    return String.valueOf(n).chars().anyMatch(i -> i % 2 == 0);
}

@State(Scope.Thread)
public static class MyState{
    public int x = 1_357_997_531;
}

@Benchmark
public void testLoop(MyState state, Blackhole blackhole) {
    boolean retVal = containsEvenDigit(state.x);
    blackhole.consume(retVal);
}

@Benchmark
public void testStream(MyState state, Blackhole blackhole) {
    boolean retVal = containsEvenDigitStream(state.x);
    blackhole.consume(retVal);
}

public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
            .include(MyBenchmark.class.getSimpleName())
            .forks(1)
            .build();

    new Runner(opt).run();
}

}

This time too the hand written loop beats the stream by an order of about 8. Here is the result summary.

Benchmark                Mode  Cnt        Score        Error  Units
MyBenchmark.testLoop    thrpt  200  3578620.170 ± 207106.919  ops/s
MyBenchmark.testStream  thrpt  200   433884.589 ±  23993.270  ops/s
Lino
  • 19,604
  • 6
  • 47
  • 65
bisarch
  • 1,388
  • 15
  • 31
  • 1
    See: https://stackoverflow.com/questions/504103 – Jorn Vernee Apr 21 '18 at 10:18
  • in one method you do `toCharArray()` and in the other `chars()` how do you know if the difference is not there? you need to provide the exact same arg to the two methods to test – Sharon Ben Asher Apr 21 '18 at 10:19
  • This questions isn't the same as https://stackoverflow.com/q/504103/802339 I asked whether Java 8 streams are slower, not about writing a flawless benchmark. – bisarch Apr 21 '18 at 10:30
  • See: https://jaxenter.com/java-performance-tutorial-how-fast-are-the-java-8-streams-118830.html – lexicore Apr 21 '18 at 10:42
  • @sank If you write *"I am trying to benchmark two different implementations"*, it is quite expected that someone points you to how to write this benchmark correctly. If you write it correctly, you have your answer. – lexicore Apr 21 '18 at 10:44
  • *"I asked whether Java 8 streams are slower"* - No you didn't. You **actually** asked *"Does this [in other words, your benchmark] mean that Java 8 streams are slower than hand written loops?"*. And the answer to that Question is that your benchmark doesn't mean anything ... because it is flawed. – Stephen C Apr 21 '18 at 11:47
  • I have another dup that asks *when* a stream will be slower than a loop. And the short answer is ... it is complicated, and Java version specific. – Stephen C Apr 21 '18 at 11:58
  • @StephenC Now I am benchmarking using JMH. The results are the same. – bisarch Apr 23 '18 at 15:00
  • OK. Now how have a single "data point". This says that for this particular example (coded as you have done it) the loop implementation is faster than the stream implementation. But you can't generalize from a single data point / single example to the conclusion you are attempting to draw. So, once again, No it doesn't mean that. – Stephen C Apr 23 '18 at 23:21

0 Answers0