I searched on the internet for a good resource about comparison between Java for loop and stream.forEach, so I needed to write an article about it myself because I couldn't find one.
In this article, I would like to discuss the differences between using the streaming API and for loops from the standpoint of long-term maintainability of the code.
To reduce maintenance costs of your projects, please do consider using the Stream API instead of for loops. It might take some investment in learning to do so, but this investment will pay off eventually, both for the project and for the engineers.
But if you are interested in performance optimization, just use classic for loops.
Stream is NOT for Looping
The purpose of Streams is not as some sort of replacement to for
loops.
If you just have a list you need to iterate over, it's obvious that Stream.forEach
isn't necessary. Stream.forEach is not for when you have a List that needs iterating.
It's for when you have constructed a Stream that requires iterating.
Using Stream.forEach
means that you get to live under your Stream's pipeline, rather than forcing your own imperative loop. Streams can exist in some way that is different from an ordinary imperative pipeline.
Actually, the only example of choosing Streams over for loop, is parallel streams, which will call your lambda in a parallel, non-sequential way, which will make the “loop” faster if the code inside the lambda is performance critical.
This will save you a few lines of code vs using an ExecutorService
, if your problem matches the performance assumptions built into Streams and Spliterators. But the point is that you have to let the Stream pipeline control when and how everything happens.
About Performance
Many people have opinions about which style performs better. The short version is that for small lists, loops work better. For big lists, a parallel stream works better. And since parallel streams have quite a bit of overhead, it is not advised to use these unless you are sure it is worth the overhead.
So although the difference is not that big, for loops win by pure performance. That being said, performance is not the only important metric to measure your code by. Everything in software engineering is a trade-off.
Performant code usually is not very readable, and readable code usually is not very performant.
Since the cost of maintenance is generally higher than the cost of hardware these days, the preference often leans towards producing readable and maintainable code.
Unless millisecond performance is mission-critical and your entire stack and software have been optimized for it, it's not usually a strong argument.
Edge Cases
In one of my previous experiences, I had a case where I had to do a nested loop. I chose Stream.forEach
, and I encountered an infinite loop caused by a StackOverflow Exception. I really struggled to find the cause of this problem, which I have to admit is still a mystery still to this day.
//...
repository.findAll()
.stream()
.map(entity -> mapper.map(entity, Model.class)
.collect(Collectors.toList())
.forEach(model -> model.getEmployees().forEach(employee -> {
System.out.println(employee)
}))
//...
But I founded a solution, which at the time was simply to refactor my code from Stream.forEach to a nested for loop (read: which gives me more flexibility in my code) to avoid having an infinite loop.
//...
for(Model model: entities) {
for(employee : model.employees) {
System.out.println(employee)
}
}
//...
I hope you enjoyed reading this, and I'm curious to hear if this tutorial helped you. Please let me know your thoughts below in the comments. Don't forget to subscribe to my newsletter to avoid missing my upcoming blog posts.
You can also find me here LinkedIn • Twitter • GitHub or Medium
Final point
In conclusion, this article provides valuable insights into why Java for loop is a more practical choice over the Stream.forEach method. By understanding the nuances of these two approaches, it enhances your coding efficiency and mastery of Java.
More References
(1) StackOverflow : Java 8 Iterable.forEach() vs forEach loop
(2) StackOverflow : Java 8 Iterable.forEach() vs forEach loop