Aravind Yarram
Aravind Yarram

Reputation: 80176

java 8 stream interference versus non-interference

I understand why the following code is ok. Because the collection is being modified before calling the terminal operation.

List<String> wordList = ...;
Stream<String> words = wordList.stream();
wordList.add("END"); // Ok
long n = words.distinct().count();

But why is this code is not ok?

Stream<String> words = wordList.stream();
words.forEach(s -> if (s.length() < 12) wordList.remove(s)); // Error—interference

Upvotes: 5

Views: 283

Answers (2)

Stuart Marks
Stuart Marks

Reputation: 132380

Joachim's answer is correct, +1.

You didn't ask specifically, but for the benefit of other readers, here are a couple techniques for rewriting the program a different way, avoiding stream interference problems.

If you want to mutate the list in-place, you can do so with a new default method on List instead of using streams:

wordList.removeIf(s -> s.length() < 12);

If you want to leave the original list intact but create a modified copy, you can use a stream and a collector to do that:

List<String> newList = wordList.stream()
    .filter(s -> s.length() >= 12)
    .collect(Collectors.toList());

Note that I had to invert the sense of the condition, since filter takes a predicate that keeps values in the stream if the condition is true.

Upvotes: 5

Joachim Isaksson
Joachim Isaksson

Reputation: 180917

Stream.forEach() is a terminal operation, and the underlying wordList collection is modified after the terminal has been started/called.

Upvotes: 6

Related Questions