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