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

Michael Eric Oberlin picture Michael Eric Oberlin · May 5, 2015 · Viewed 87.6k times · Source

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?

Answer

Paul Boddington picture Paul Boddington · May 5, 2015

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();
    }
}