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());
最后,控制台打印一个NullPointerException
错误。CoreJava说我们不应该修改Collection,它将在修改后返回流。而且我对这个原理没有一个清晰的理解。
传递给forEach
的Consumer
必须是无干扰的。其理由如下所述。
无干扰
流使您能够对各种数据源执行可能的并行聚合操作,甚至包括ArrayList等非线程安全集合。只有当我们能够在流管道的执行过程中防止对数据源的干扰时,这才有可能。除了转义填充操作迭代器((和拆分器((之外,执行从调用终端操作时开始,到终端操作完成时结束对于大多数数据源,防止干扰意味着确保数据源在流管道执行过程中不会被修改。值得注意的例外是,流的源是并发集合,它们是专门为处理并发修改而设计的。并发流源是指Spliterator报告具有并发特性的流源。
(来源(
顺便说一句,即使上一个stringStream.forEach()
语句没有,您的stringStream.count()
也会失败,因为forEach
(与任何终端操作一样(会消耗Stream
,而Stream
不能消耗两次。
实现您想要做的事情的正确方法是过滤原始的List
并创建新的List
:
List<String> filtered =
list.stream()
.filter(m->!m.equals("banana"))
.collect(Collectors.toList());
不能使用流从列表中删除元素,但可以通过调用removeIf()
来使用lambda表达式。
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
List<String> list = new ArrayList<>()
{
{
add("apple");add("banana");add("orange");
}
};
Stream<String> stringStream = list.stream();
final long counter = stringStream.filter(Predicate.not("banana"::equals))
.count();
System.out.println(counter);