我对范围,流和重新分配有疑问。
我想知道是否有一种方法可以使用流式api而不重新分配列表。重新分配参数的问题是它破坏了范围,因此测试看不到新值。
我知道还有其他方法(迭代器,向后迭代等)可以解决问题。这个问题只是出于好奇。
测试代码:
@Test
void testAllNegativesByIterator() {
List<Integer> values = new ArrayList<>(Arrays.asList(-1, -2, -3, -4, -5, -6, -7, -8, -9));
p.removeNegativesByIterator(values);
checkNonNegativeSize(0, values);
}
正在测试的代码:
public void removeNegativesByStream(List<Integer> values) {
values = values.stream().filter(v -> v > 0).collect(Collectors.toList());
}
编辑:
我也知道我可以返回一个值。就像我在问题中所说的那样,我特别想问一种出于好奇而使用流的方法。
答案 0 :(得分:6)
首先,在方法调用为java doesn't support pass by reference之后,流查询的结果重新分配回values
不会持续。
关于这个问题:
您可以使用Collection::removeIf
方法来删除源集合中满足给定谓词的所有元素:
values.removeIf(v -> v <= 0);
否则,您别无选择,只能创建一个新列表,因为流不会修改源。
答案 1 :(得分:0)
您希望Stream API对基础集合进行突变,这与Streams的功能本质背道而驰。纯函数没有副作用。您可以在方法中更改列表,从而避免重新分配,但不使用流。
public void removeNegativesByStream(List<Integer> values) {
List<Integer> original = new ArrayList<>(values);
values.clear();
values.addAll(original.stream().filter(v -> v > 0).collect(Collectors.toList()));
}
答案 2 :(得分:0)
首先,除了是否使用Streams API之外,您在做什么都是错误的。
在Java中,您不能为方法参数重新分配新引用,因为Java不支持按引用传递。
您的未引入流管道的代码段完全等同于以下示例:
public void removeNegativesByStream(List<Integer> values) {
values = null;
}
将values
重新分配给null
仅在方法范围内可见,它永远不会泄漏出去,并且无论是否使用Streams API都适用。
当您面对使用新的Streams API对源集合进行变异时,您根本无法这样做,因为流管道只是对数据源的一次一次运行传递(在您的示例values
)。
您可以做的是将管道的结果收集到仅包含正数的新List<Integer>
中,但这不会影响您的values
变量和下一个测试(checkNonNegativeSize(0, values);
)只会失败。
现在,您剩下其他解决方案了,其中包括通过列表的迭代器手动删除负数,或使用声明性包装器Collection#removeIf描述要从集合中删除哪些元素。
我想到的最有效,最易读的解决方案是Aomine's solution。