List<String> list = new ArrayList(){{add("apple");add("banana");add("orange");}};
Stream<String> stringStream = list.stream();
stringStream.forEach(
m->{
if (m.equals("banana")){
list.remove("banana");
}
}
);
System.out.println(stringStream.count());
Fianlly, the console prints a NullPointerException
error. The CoreJava says that we shouldn't modify the Collection which will return back to the stream after modified. And I don't have a clear understanding of the principle.
Once we've finished operating on the items in the stream, we can remove them using the same Predicate we used earlier for filtering: itemList. removeIf(isQualified); Internally, removeIf uses an Iterator to iterate over the list and match the elements using the predicate.
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.
The Consumer
passed to forEach
must be non-interfering. The reasoning is explained below.
Non-interference
Streams enable you to execute possibly-parallel aggregate operations over a variety of data sources, including even non-thread-safe collections such as ArrayList. This is possible only if we can prevent interference with the data source during the execution of a stream pipeline. Except for the escape-hatch operations iterator() and spliterator(), execution begins when the terminal operation is invoked, and ends when the terminal operation completes. 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.
(Source)
BTW, your stringStream.count()
would have failed even if the previous stringStream.forEach()
statement did not, since forEach
(as any terminal operation) consumes the Stream
, and a Stream
cannot be consumed twice.
The correct way to achieve what you were trying to do is to filter the original List
and create a new List
:
List<String> filtered =
list.stream()
.filter(m->!m.equals("banana"))
.collect(Collectors.toList());
You can't use streams to remove elements from a list, but you can use lambda expression by calling removeIf()
.
List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "orange"));
list.removeIf(m -> m.equals("banana")); // or: list.removeIf("banana"::equals)
System.out.println(list); // prints: [apple, orange]
System.out.println(list.size()); // prints: 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With