Of Java Streams … Again!

Posted by & filed under .

JAX London LogoI just went again through this JAX London write-up (read more here: http://www.infoq.com/news/2015/10/jax-london-2015-round-up) and thought it was worth some more thoughts from me.

As you might recall, I have touched before on the subject of Java 8 streams in this blog post back in Sep/2014. The thing that puzzled me back then was the fact that using a streams-based implementation for small things (such as searching for an item in an array in that case) rendered quite a huge difference in speed — in this particular case, my measurements, while not precisely accurate, showed still that streams implementation was about 6 times slower than the sequential standard implementation. I can even take on the argument that my experience with streams in Java at the time was not quite there and as such code could be re-organized and optimized but even so one stream-efficient coder would still only get the stream-based code to perform close to the sequential implementation!

It seems at JAX London 2015, Angelika Langer presented a comparison of sequential vs stream-based implementations. Based on her analysis, it seems that streams are, at best, as efficient as the for-loop, and oftentimes worse. I didn’t spend too much effort at the time I published my blog post to look into why that might be, but Angelika sheds some light into this: the main reason seems to be that the iteration cost itself in a for-loop is lower than that of a sequential stream; if the operation (or operations) being executed at each iteration is computationally heavy, then the cost of this will eclipse the cost of the iteration itself, and for-loops and streams will show similar performance. However, if the operation being executed at each iteration is lightweight, then the cost of the iteration will gain importance, and for-loops will be noticeably faster. In other words, if your for-loop does a simple increment at each step (to increment the index in an array for instance) then your for-loop is gonna fly past the streams implementation!

The analysis dives a bit deeper into this comparison than my original post as she also looks at using also parallel streams — to render a similar result still! This time of course, one has to pay the price for thread context switching and thread management inside the JVM. There are some interesting results in this case from Angelika, as it seems doing something like this with a LinkedList (which is notoriously bad for random accessing elements!) showcases a 65% decrease in speed in the case of parallel streams. (Though I would have liked to see that being performed against a simple array?)

I am not even more intrigued in streams — and will need to check what the Java 9 release announces around it — on one hand, these seem a very elegant way of coding in java using functional programming, on the other hand, most of the solutions I work on are in the advertising space where milliseconds count, so it seems as of yet Java streams can’t really play a significant role in these solutions. Which saddens me a bit, as this suggests that working on something like a RTB system automatically means you cannot embrace some of these new features of the language… Hopefully new JDK releases will sort this out?


Update 09-Dec-2015

Interestingly enough, having posted this yesterday, this post on DZone on Java streams and lambdas got published today — talk about perfect timing! The article is worth reading as it analyzes the impact of the Java 8 streams and lambdas to code performance. It also turns out the author went through 2 iterations of the post: the very first one showcased a huge decrease in performance when looking at lambdas and stream versus classic for-loops. (It was in fact this huge difference that warranted the title of the post: “How Java 8 Lambdas and Streams Can Make Your Code 5 Times Slower “) However, it seems a lot of feedback from the community was received around the way to write some of the code around streams and lambdas such that in the end some of the tests rendered similar results to the classic for-loop.

I have the feeling now reading this even more so that streams and lambdas need at this moment in time a lot of lovin’ if you decide to embrace them — and quite likely my initial post on this matter has fallen in similar traps — otherwise your performance could suffer. (Though you can make the same argument for any framework and library, for sure 🙂 ) Bottom line, for me the jury is still out on this: I DO like the concept of streams and lambdas in Java 8, I do NOT like paying a big performance price for it… tough one, huh?