lambda 中的 Java 8 lambda 无法修改来自外部 lambda 的变量

标签 java lambda java-8

假设我有一个 List<String>和一个 List<Transfomer> .我想将每个转换器应用于列表中的每个字符串。

使用 Java 8 lambda,我可以这样做:

strings.stream().map(s -> {
    for(Transformer t : transformers) {
        s = t.apply(s);
    }
    return s;
}).forEach(System.out::println);

但我想做更像这样的事情,但是它会导致编译时错误:

strings.stream().map(s -> transformers.stream().forEach(t -> s = t.apply(s))).forEach(System.out::println);

我刚刚开始使用 lambda,所以可能我的语法不正确。

最佳答案

对流执行此操作的最佳方法是使用 reduce:

// make a transformer that combines all of them as one
Transformer combinedTransformer =

    // the stream of transformers
    transformers.stream()

    // combine all the transformers into one
    .reduce(

        // apply each of the transformers in turn
        (t1, t2) -> x -> t2.apply(t1.apply(x)))

    );



// the stream of strings
strings.stream()

// transform each string with the combined transformer
.map(combinedTranformer::apply);

当然,这假设 transformers 是非空的;如果它有可能为空,那么使用 reduce 的双参数重载就足够简单了,就像这样(这假设 Tranformer 是一个功能接口(interface)):

// make a transformer that combines all of them as one
Transformer combinedTransformer =

    // the stream of transformers
    transformers.stream()

    // combine all the transformers into one
    .reduce(

        // the no-op transformer
        x -> x,

        // apply each of the transformers in turn
        (t1, t2) -> x -> t2.apply(t1.apply(x)))

    );



// the stream of strings
strings.stream()

// transform each string with the combined transformer
.map(combinedTranformer::apply);

你得到编译器错误的原因是,正如错误所说,lambda 表达式中使用的外部变量必须有效地结束;也就是说,声明它们 final(如果它们还没有)不能改变程序的含义,或者改变它是否编译。因此,在 lambda 中使用可变赋值通常是被禁止的,并且有充分的理由:突变搞砸了并行化,而 Java 8 中包含 lambda 的主要原因之一是允许更容易的并行编程。

一般来说,只要您想以某种方式“总结”结果,reduce(在其三个重载中的任何一个)都是您的首选方法。在使用 时,学习如何有效地使用 mapfilterreduceflatMap 非常重要流

关于lambda 中的 Java 8 lambda 无法修改来自外部 lambda 的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23451579/

相关文章:

c++ - Lambda 上的运算符 +

java - 捕获 lambda 表达式的池

java - 从 HashMap 获取可比键的时间

java - 如何自定义使用 Hibernate 的 hbm2ddl(使用注释)生成的 DDL?

java - 列表索引超出 map 的范围以减少Java中的作业

c# - LINQ 表达式的运行时创建

java - 我在哪里可以找到 Java 库中 `native` 方法的源代码?

java - 关于基于 SOAP 的网络服务

java - Hibernate 可选继承

python - 为什么 python lambda 看到的是一个序列而不是一个值?