java - BiFunction - apply 方法应该总是返回第二个参数。为什么?

标签 java lambda java-stream

我正在尝试从列表中识别其前身大于其值的数字。

在 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减少的作为累加器的第一个参数传递,当前 elementStream作为第二个参数传递。

因此,当您的 lambda 表达式返回第二个参数时 b (第一个片段),中间结果成为 Stream 的当前元素,您将其添加到 List在下一次迭代中。

当您的 lambda 返回第一个参数时 a (第二个片段),中间结果保持不变(总是 1Stream 的第一个元素),并且您继续将该值添加到 List .

让我们用实际数字来验证一下:

result被初始化为 Stream 的第一个元素 1 .

然后,第一个片段调用 accumulator.apply(1,2) , 添加 1List并返回 2 (成为新的中间结果)。下一次迭代将添加 2List并返回 3 .等等……

第二个片段调用 accumulator.apply(1,2) , 添加 1List并返回 1(它仍然是新的中间结果)。下一次迭代将添加 1List再次返回1再次。等等……

总而言之,您的两个累积函数具有不同的功能:

第一个结果是 Stream 的最后一个元素(因为它不断丢弃当前结果并将其替换为当前元素)。

第二个结果是 Stream 的第一个元素(因为它保留第一个元素并忽略所有其他元素)。

关于java - BiFunction - apply 方法应该总是返回第二个参数。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57303324/

相关文章:

java - 在单个项目中使用 SBT 和 Maven?

java - 查找我的组件是否是其他组件的祖先

java - Play Framework 2.5 应用程序在没有明显原因的情况下崩溃

java - 使用条件转换 HashMap 中的 Stream

java - 当路径包含空间时,如何在 Windows 8 上的 eclipse.ini 中指定 jdk 路径

C++14 lambda 的默认参数类型推导取决于前面的参数

c++17:lambda 到 std::function 转换失败

c# - Func<> 与委托(delegate)和 lambda 表达式之间的区别

Java 8 Streams在过滤map后获取原始对象

java - 了解链式 CompletableFuture 的并行执行