I'm currently taking on a project where I'm measuring the speed of different types of loops in Java using the Java Microbenchmark Harness (JMH) framework. I got some interesting results regarding streams which I can't explain and was wondering if someone who understands streams and Array Lists better could maybe help me explain my results.
Basically, when iterating through Array Lists around sizes of 100, the stream.forEach method is much much faster than any other type of loop:
A graph of my results is shown here: https://i.sstatic.net/W34eA.png
I've tried using Array Lists of both objects and strings and all produce similar results. As the size of the list gets bigger, the stream method is still faster, but the performance gap between other lists gets smaller. I have no idea what is causing these results.
@Fork(5)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 10, time = 100, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 100, timeUnit = TimeUnit.MILLISECONDS)
@State(Scope.Thread)
public class StackOverflowQ {
List<Integer> intList;
int size = 100;
@Setup
public void setup() {
intList = new ArrayList<>(size);
for(int i = 0; i<size;i++){
intList.add(i);
}
}
/**
Work done to each item in the loop.
*/
public double doWork(int item) {
return item + 47;
}
@Benchmark
public void standardFor(Blackhole bh){
for (int i = 0; i<intList.size(); i++){
bh.consume(doWork(intList.get(i)));
}
}
@Benchmark
public void streamForEach(Blackhole bh){
intList.stream().forEach(i -> bh.consume(doWork(i)));
}
}
size()
call from the loop (usesize
instead ofintList.size()
) - check https://mcmap.net/q/1772596/-for-and-foreach-loops-how-to-create-them-most-efficiently/85421 – Gambogesequential()
? For the sake of correctness, I would include this explicit call in your benchmark. – Puentesfor(Integer i: intList) bh.consume(doWork(i));
variant. Further, you can useforEach
on theArrayList
directly, without a Stream. – Previse