Like just about everyone, I'm still learning the intricacies (and loving them) of the new Java 8 Streams API. I have a question concerning usage of streams. I'll provide a simplified example.
Java Streams allows us to take a Collection
, and use the stream()
method on it to receive a stream of all of its elements. Within it, there are a number of useful methods, such as filter()
, map()
, and forEach()
, which allow us to use lambda operations on the contents.
I have code that looks something like this (simplified):
set.stream().filter(item -> item.qualify()) .map(item -> (Qualifier)item).forEach(item -> item.operate()); set.removeIf(item -> item.qualify());
The idea is to get a mapping of all items in the set, which match a certain qualifier, and then operate through them. After the operation, they serve no further purpose, and should be removed from the original set. The code works well, but I can't shake the feeling that there's an operation in Stream
that could do this for me, in a single line.
If it's in the Javadocs, I may be overlooking it.
Does anyone more familiar with the API see something like that?
Java Collections framework is used for storing and manipulating group of data. It is an in-memory data structure and every element in the collection should be computed before it can be added in the collections. Stream API is only used for processing group of data.
An element can be removed from a Collection using the Iterator method remove(). This method removes the current element in the Collection. If the remove() method is not preceded by the next() method, then the exception IllegalStateException is thrown.
If we want to use the concept of streams then stream () is the method to be used. Stream is available as an interface. In the above pre-tag, ‘c’ refers to the collection. So on the collection, we are calling the stream () method and at the same time, we are storing it as the Stream object. Henceforth, this way we are getting the Stream object.
Introduced in Java 8, the Stream API is used to process collections of objects. A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. Before proceeding further let us discuss out the difference between Collection and Streams in order to understand why this concept was introduced.
It internally uses a java.util.StringJoiner to perform the joining operation. We can also use toSet () to get a set out of stream elements: We can use Collectors.toCollection () to extract the elements into any other collection by passing in a Supplier<Collection>.
Java Streams allows us to take a Collection, and use the stream () method on it to receive a stream of all of its elements. Within it, there are a number of useful methods, such as filter (), map (), and forEach (), which allow us to use lambda operations on the contents.
You can do it like this:
set.removeIf(item -> { if (!item.qualify()) return false; item.operate(); return true; });
If item.operate()
always returns true
you can do it very succinctly.
set.removeIf(item -> item.qualify() && item.operate());
However, I don't like these approaches as it is not immediately clear what is going on. Personally, I would continue to use a for
loop and an Iterator
for this.
for (Iterator<Item> i = set.iterator(); i.hasNext();) { Item item = i.next(); if (item.qualify()) { item.operate(); i.remove(); } }
In one line no, but maybe you could make use of the partitioningBy
collector:
Map<Boolean, Set<Item>> map = set.stream() .collect(partitioningBy(Item::qualify, toSet())); map.get(true).forEach(i -> ((Qualifier)i).operate()); set = map.get(false);
It might be more efficient as it avoids iterating the set two times, one for filtering the stream and then one for removing corresponding elements.
Otherwise I think your approach is relatively fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With