I am not entirely sold on the performance of the Java streams but I will accept they are getting much better compared to the first cut, we now have parallel streams and all sorts, and also it provides a (nicer) functional approach to coding. I’m not going to go into the whole dispute of whether functional style is better than object oriented, I use both and more often than not I actually both in the same project.
And I have found out that it provides us with nicer ways of implementing some “classic” issues we come across every now and them when writing Java code.
Let’s look at some of these together and how much nicer (and denser!) can our code look using Java streams.
Finding the max value
Let’s consider the simple example of finding the max integer in a
Collection. Without streams this is the code you’d be looking at:
Now let’s look at what would the equivalent code look like when we employ Java streams:
Damn! It pretty much comes down to 1 single line! And also it takes care of empty streams and nicely supplies an
Optional. (Ok, ok, I know there is nothing preventing me in the first version from dealing nicely with empty collections and returning an
Optional there, but be honest: people who haven’t started looking at Java 8 Streams for this how likely are they to write code like the above and use an
Now it doesn’t end here. This is a simple case of finding the max in an array of integers. But what if I want something a bit more “complicated” such as given a collection of “structures” such as employees I want to find the one with the highest salary?
Again, in “old school” Java we would simply write:
Now the stream-based implementation:
Boom! One-liner again 🙂
Finding items in a collection
Let’s now say we want to extract only the elements which match a certain criteria. For simplicity let’s find, using the same
Employee class as before, only the people called “Bob”. (The plan here of course would be to pair them in 2’s and set up consultancy companies called “The Bobs” and send them out to charge big bucks and help companies downsize 🙂
Here’s what our code would look like with no streams:
Now let’s see how we would do it with streams:
I have provided here a few implementations which showcase also how easy it is to change the underlying Collection implementation. Of course, it’s not that difficult to change the non-stream based implementation either: we just change
List<Employee> list = new ArrayList<>() to something like
Set<Employee> list = new HashSet<>() but the stream approach is more compact, you must admit.
Extract data member from elements of a collection (map)
This one I see rather often: we have a collection of a certain class (let’s say
Employee) in this case and we want to extract only certain data from each instance (let’s say the salary) and build a collection with the result data. Again, the usage is clear, we want to extract all the salaries we pay our employees and employ a complicated formula — read “max” — to decide what our “Bob and Bob Enterprise” should charge its clients! 🙂
In the non-stream world we would write this:
This is not too bad right?
Well until you see this stream-based implementation:
All of the above
Now what if I want to combine all of these (for a piece-de-resistance)? What if I want to find all employees called “Bob”, extract all their salaries then find out the max? Just so we can put that on our TPS reports in the cover letter 😉
In non-streams world we would combine all of these methods right? So our code would be:
There’s a lot of brackets there at the end 🙂 And a lot of lines of code. Could we do better with streams?
Ahem, this damn thing is still one line whatever I do 🙂 though to be honest I would recommend you have each stream operation on its own line so it’s easier to read them sequentially:
max, this way you can just glance at the code and see what your code is performing on the stream and just focus on the step which creates problems.
This list doesn’t stop here and in fact I’m planning on reviewing this in a couple of weeks and add to it; the idea I am trying to push out there is that the Java streams are still not the most performant (though you want a similar functional approach — and in fact methods that are pretty much named the same as here for consistency — have a look at RxJava which will probably put your app on steroids!) but they can save you a ton of boilerplate code. For your standard UI or ETL or non-critical code you can safely switch to them and save yourself a lines of code to write.