我正在尝试从列表中识别其前身大于其值的数字。
在 lambda 表达式中,如果我返回 b,它的行为符合预期,但如果我返回 a,它会给出错误的输出。
这两个返回语句有什么区别?
List<Integer> list = Arrays.asList(1,2,3,4,5,8,7);
List<Integer> result = new ArrayList<>();
list.stream().reduce((a,b) -> {if (a < b) result.add(a);return b;});
System.out.println(result);
result.clear();
list.stream().reduce((a,b) -> {if (a < b) result.add(a);return a;});
System.out.println(result);
输出:
[1, 2, 3, 4, 5]
[1, 1, 1, 1, 1, 1]
最佳答案
您正在执行的减少 - 使用 Optional<T> java.util.stream.Stream.reduce(BinaryOperator<T> accumulator)
- 等效于以下伪代码(取自 Javadoc):
boolean foundAny = false;
T result = null;
for (T element : this stream) {
if (!foundAny) {
foundAny = true;
result = element;
} else {
result = accumulator.apply(result, element);
}
}
return foundAny ? Optional.of(result) : Optional.empty();
如您所见,中间体 result
减少的作为累加器的第一个参数传递,当前 element
的 Stream
作为第二个参数传递。
因此,当您的 lambda 表达式返回第二个参数时 b
(第一个片段),中间结果成为 Stream
的当前元素,您将其添加到 List
在下一次迭代中。
当您的 lambda 返回第一个参数时 a
(第二个片段),中间结果保持不变(总是 1
, Stream
的第一个元素),并且您继续将该值添加到 List
.
让我们用实际数字来验证一下:
result
被初始化为 Stream 的第一个元素 1
.
然后,第一个片段调用 accumulator.apply(1,2)
, 添加 1
到 List
并返回 2
(成为新的中间结果)。下一次迭代将添加 2
到 List
并返回 3
.等等……
第二个片段调用 accumulator.apply(1,2)
, 添加 1
到 List
并返回 1(它仍然是新的中间结果)。下一次迭代将添加 1
到 List
再次返回1
再次。等等……
总而言之,您的两个累积函数具有不同的功能:
第一个结果是 Stream
的最后一个元素(因为它不断丢弃当前结果并将其替换为当前元素)。
第二个结果是 Stream
的第一个元素(因为它保留第一个元素并忽略所有其他元素)。
关于java - BiFunction - apply 方法应该总是返回第二个参数。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57303324/