Nik*_*las 29 java java-8 java-stream
以下陈述是真的吗?
该
sorted()操作是"有状态的中间操作",这意味着后续操作不再对后备集合进行操作,而是对内部状态进行操作.
我已经测试Stream::sorted过以上来源的片段:
final List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());
list.stream()
.filter(i -> i > 5)
.sorted()
.forEach(list::remove);
System.out.println(list); // Prints [0, 1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)
有用.我替换Stream::sorted为Stream::distinct,Stream::limit和Stream::skip:
final List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());
list.stream()
.filter(i -> i > 5)
.distinct()
.forEach(list::remove); // Throws NullPointerException
Run Code Online (Sandbox Code Playgroud)
令我惊讶的NullPointerException是,它被扔了.
所有测试方法都遵循有状态中间操作特性.然而,Stream::sorted没有记录这种独特的行为,Stream操作和管道部分解释了有状态中间操作是否真正保证了新的源集合.
我的困惑来自何处以及上述行为的解释是什么?
Hol*_*ger 31
API文档没有保证"后续操作不再对后备集合进行操作",因此,您永远不应该依赖于特定实现的这种行为.
你的例子偶然发生了想要的事情; 甚至没有保证所List创建的collect(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);
Run Code Online (Sandbox Code Playgroud)
抛出一个ConcurrentModificationException.原因是实现优化了这种情况,因为源已经排序.原则上,它可以对原始示例forEach执行相同的优化,因为显式执行没有指定顺序的操作,因此,排序是不必要的.
还有其他可以想象的优化,例如sorted().findFirst()可以转换为"查找最小"操作,而无需将元素复制到新存储中进行排序.
因此,最重要的是,当依赖于未指明的行为时,今天可能发生的事情,明天可能会在新增优化时加入.
那么sorted必须是一个完整的复制了流管道不通,毕竟你的来源可能是没有排序 ; 但这并没有记录,因此不依赖它.
这不仅仅是关于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
Run Code Online (Sandbox Code Playgroud)
当然,sorted需要成为一个完整的障碍并停下来进行整个排序,当然,除非它可以被跳过,因此文档没有做出这样的承诺,因此我们不会遇到奇怪的意外.
distinct另一方面,不必是一个完整的障碍,所有不同的做法是一次检查一个元素,如果它是唯一的; 因此,在检查单个元素(并且它是唯一的)之后,它将被传递到下一个阶段,因此不会成为完整的障碍.无论哪种方式,这也没有记录......
| 归档时间: |
|
| 查看次数: |
1352 次 |
| 最近记录: |