Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Java 8 Streams operate on an item in a collection, and then remove it?

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?

like image 457
Michael Macha Avatar asked May 04 '15 22:05

Michael Macha


People also ask

What is the correct difference between collection and stream in Java 8?

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.

How do I remove an item from a collection in Java?

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.

How to get the stream object from a collection in Java?

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.

What is a stream in Java 8?

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.

How to get a set out of stream elements in Java?

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>.

How do I get the contents of a collection in Java?

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.


2 Answers

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();     } } 
like image 75
Paul Boddington Avatar answered Sep 20 '22 14:09

Paul Boddington


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.

like image 25
Alexis C. Avatar answered Sep 19 '22 14:09

Alexis C.