Recently, I have written a class that looked roughly like this:
public class Requirement { ...
public Requirement(...) { ...
}
public When getWhen() { ...
}
public Event getEvent() {...
}
public SystemReaction getSystemReaction() {...
}
}
I had a list of Requirement
instances. Now, I needed the set of Event
instances that was referenced by at least one Requirement
. An Event
instance could also be null
.
In Java before Java 8, I would have done the following:
a) Create an empty HashSet
b) Iterate over the list of Requirement
instances
c) For each Requirement
instance, check if getEvent()
returns null
d) If it does not return null
, add the event to the HashSet
Starting with Java 8, you can use streams to accomplish this task in a one-liner:
Set<Event> events = requirements.stream().map(req -> req.getEvent())
.filter(event -> event != null).collect(Collectors.toSet());
To find out more about streams, check out this tutorial.
Top comments (6)
You could even replace .filter(event -> event != null) with .filter(Objects::nonNull) !
Another awesome note: when calling .parallel() on a stream, every further task in the pipeline gets executed in parallel using the default forkjoinpool, which uses exactly the number of cores available minus 1 (for the main thread). Awesome for speeding up tasks in some situations!
You're right. I created this based on an example with deeper nesting, and kept it in as I thought it might be easier to grasp for somebody new to the topic.
(1) I assumed it was because of a reason like that, but still wanted to give a hint for those who might appreciate it. I'd consider it a cleaner and more readable solution.
(2) This is definitely for more advanced users, but is such a powerfull tool, that I thought it should definitely be mentioned.
I tend to write this in the following way, as it optimizes for clarity:
I love Java's streams, but still there is one thing which I hate about them. Verbosity where it's really not necessary and I see just one case where it's not necessary - for collectors. Every time we want to terminate a stream by getting collection from it, we had to do this ugly "collect(Collectors.toSomthieng())". I know, I know. It enables us to provide our custom collectors, but I don't see why Stream class does not have simple method "toList()" and "toSet()". These are the most common cases! Have a look: "stream.collect(Collectors.toList())" vs "stream.toList()". I didn't do any research, but I bet toList and toSet operations are like 80% of cases. Why not make this simpler? We still could use collect() for more customization, but lack of toList() and toSet() in the Stream is such a pain! Having such methods comes directly from intuition. These are the first which people look like when they learn Stream. It's not lost, since we have default methods and future Java versions may introduce these methods. I hope so. Maybe there's already such proposal and I just couldn't find it?
I understand your pain :-) As far as I know, the vavr library tries to solve that problem.