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

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.


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.

You cannot remove elements from the source of the stream with the stream. From the Javadoc:

Most stream operations accept parameters that describe user-specified behavior..... To preserve correct behavior, these behavioral parameters:

  • must be non-interfering (they do not modify the stream source); and
  • in most cases must be stateless (their result should not depend on any state that might change during execution of the stream pipeline).

There are many approaches. If you use myList.remove(element) you must override equals(). What I prefer is:

allList.removeIf(item -> item.getId().equals(elementToDelete.getId()));

Good luck and happy coding :)


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