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

2023-11-24

假设我有一个List<String> and a 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是一个函数式接口):

// 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 中使用可变赋值通常是被禁止的,并且有充分的理由:突变会破坏并行化,而 lambda 包含在 Java 8 中的主要原因之一是允许更轻松的并行编程。

一般来说,每当你想以某种方式“总结”结果时,reduce(在其三个重载中的任何一个中)是您的首选方法。学习如何使用map, filter, reduce, and flatMap与他人合作时,有效地非常重要Streams.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

lambda 内的 Java 8 lambda 无法修改外部 lambda 中的变量 的相关文章

随机推荐