stu*_*ent 5 java java-8 java-stream
我编写了以下代码来测试修改流的后备集合的副作用
List<Integer> x = new ArrayList<>(Arrays.asList(1, 11, 21));
x.stream().filter(i -> {
if (i < 10) {
x.remove(i);
return false;
}
return true;
}).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
输出将是
21
Exception in thread "main" java.lang.NullPointerException
Run Code Online (Sandbox Code Playgroud)
谁能告诉我这里到底发生了什么?特别是,NullPointerException来自哪里?谢谢.
您通过传递干扰谓词违反了合同filter.有关非干扰要求的详细说明,请参见此处.它具体说:
不干涉的需要适用于所有管道,而不仅仅是并行管道.除非流源是并发的,否则在执行流管道期间修改流的数据源可能会导致异常,错误答案或不一致的行为.
因此,您的问题的答案是,由于某些未指定的实现细节,您运行的java版本以特定方式使用该特定数据失败.不同版本的java可能会以某种其他方式失败,或者不抛出任何内容并产生您期望的答案或产生错误的答案.
您可以使用Collection指定生成CONCURRENT spliterator的方法尝试:
Collection<Integer> x = new ConcurrentLinkedQueue<>(Arrays.asList(1, 11, 21));
Run Code Online (Sandbox Code Playgroud)
它应该做你期望的,而不是抛出任何异常.
要了解它,我们可以制作一个关于完全发生的模式:
你的清单看起来像这样:
+---+ +---+ +---+
| 1 | --> |11 | --> |21 |
+---+ +---+ +---+
0 1 2
Run Code Online (Sandbox Code Playgroud)
现在过滤器的工作将按索引迭代列表索引
第一次迭代(索引= 0,i = 1)
检查是否i < 10- >是然后从列表中删除它.现在看起来像这样:
+---+ +---+ +-----+
|11 | --> |21 | --> |null |
+---+ +---+ +-----+
0 1 2
Run Code Online (Sandbox Code Playgroud)
第二次迭代(索引= 1,i = 21不是11)
检查是否i < 10- >是然后从列表中删除它.现在看起来像这样:
+---+ +-----+ +-----+
|21 | --> |null | --> |null |
+---+ +-----+ +-----+
0 1 2
Run Code Online (Sandbox Code Playgroud)
第三次迭代(index = 2,i = null)
检查是否i < 10意味着null < 10- >这将抛出NullPointerException.
现在的问题是,你为什么这样做?所有你需要的只是:
x.removeIf(i -> i < 10);
x.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
164 次 |
| 最近记录: |