3 回答
TA贡献1796条经验 获得超4个赞
API 文档不保证“后续操作不再对后备集合进行操作”,因此,您永远不应该依赖特定实现的这种行为。
你的例子碰巧不小心做了想要的事情;甚至不能保证Listcreated bycollect(Collectors.toList())支持该remove操作。
展示一个反例
Set<Integer> set = IntStream.range(0, 10).boxed()
.collect(Collectors.toCollection(TreeSet::new));
set.stream()
.filter(i -> i > 5)
.sorted()
.forEach(set::remove);
抛出一个ConcurrentModificationException. 原因是实现优化了这个场景,因为源已经排序。原则上,它可以对您的原始示例进行相同的优化,因为forEach没有指定的顺序显式执行操作,因此,排序是不必要的。
还有其他可以想象的优化,例如sorted().findFirst()可以转换为“找到最小值”操作,而无需将元素复制到新的存储中进行排序。
所以底线是,当依赖未指定的行为时,今天可能发生的事情,明天可能会在添加新的优化时崩溃。
TA贡献1775条经验 获得超8个赞
Wellsorted必须是流管道的完整复制屏障,毕竟您的源可能无法排序;但这并没有记录在案,因此不要依赖它。
这不仅仅是关于sorted本身,而是可以对流管道进行哪些其他优化,因此sorted可以完全跳过。例如:
List<Integer> sortedList = IntStream.range(0, 10)
.boxed()
.collect(Collectors.toList());
StreamSupport.stream(() -> sortedList.spliterator(), Spliterator.SORTED, false)
.sorted()
.forEach(sortedList::remove); // fails with CME, thus no copying occurred
当然,sorted需要是一个完整的屏障并停止做一个完整的排序,除非,当然,它可以被跳过,因此文档没有做出这样的承诺,所以我们不会在奇怪的惊喜中运行。
distinct另一方面,不必是完整的屏障,所有不同的只是一次检查一个元素,如果它是唯一的;所以在检查单个元素(并且它是唯一的)之后,它会被传递到下一个阶段,因此不会成为一个完整的障碍。无论哪种方式,这也没有记录......
TA贡献1993条经验 获得超5个赞
您不应该使用终端操作提出案例,forEach(list::remove)
因为它list::remove
是一种干扰功能,并且违反了终端操作的“不干扰”原则。
在想知道为什么不正确的代码片段会导致意外(或未记录)的行为之前,遵守规则至关重要。
我相信这list::remove
是问题的根源。如果您为forEach
.
添加回答
举报