Modifying Objects within stream in Java8 while iterating

Solution 1:

Yes, you can modify state of objects inside your stream, but most often you should avoid modifying state of source of stream. From non-interference section of stream package documentation we can read that:

For most data sources, preventing interference means ensuring that the data source is not modified at all during the execution of the stream pipeline. The notable exception to this are streams whose sources are concurrent collections, which are specifically designed to handle concurrent modification. Concurrent stream sources are those whose Spliterator reports the CONCURRENT characteristic.

So this is OK

  List<User> users = getUsers();
  users.stream().forEach(u -> u.setProperty(value));
//                       ^    ^^^^^^^^^^^^^
//                        \__/

but this in most cases is not

  users.stream().forEach(u -> users.remove(u));
//^^^^^                       ^^^^^^^^^^^^
//     \_____________________/

and may throw ConcurrentModificationException or even other unexpected exceptions like NPE:

List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());

list.stream()
    .filter(i -> i > 5)
    .forEach(i -> list.remove(i));  //throws NullPointerException

Solution 2:

The functional way would imho be:

import static java.util.stream.Collectors.toList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class PredicateTestRun {

    public static void main(String[] args) {

        List<String> lines = Arrays.asList("a", "b", "c");
        System.out.println(lines); // [a, b, c]
        Predicate<? super String> predicate = value -> "b".equals(value);
        lines = lines.stream().filter(predicate.negate()).collect(toList());

        System.out.println(lines); // [a, c]
    }
}

In this solution the original list is not modified, but should contain your expected result in a new list that is accessible under the same variable as the old one