lambda中的Java 8 lambda无法修改外部lambda中的变量 [英] Java 8 lambda within a lambda can't modify variable from outer lambda

查看:250
本文介绍了lambda中的Java 8 lambda无法修改外部lambda中的变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Suppose I have a List<String> and a List<Transfomer>. I want to apply each transformer to each string in the list.

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

Using Java 8 lambdas, I can do this:

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

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

But I'd like to do something more like this, however it results in a compile time error:

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

我刚开始玩lambdas,所以也许我只是没有正确的语法。

I'm just starting to play with lambdas, so maybe I just don't have the syntax correctly.

推荐答案

使用stream执行此操作的最佳方法是使用 reduce

The best way to do this with streams is to use 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);

当然,这假设变形金刚是非空;如果它有可能是空的,那么使用 reduce 的双参数重载就足够了,就像这样(假设 Tranformer 是一个功能界面):

Of course, this assumes that transformers is non-empty; if there is a possibility that it is empty, than it is simple enough to use the two-argument overload of reduce instead, like so (this assumes Tranformer is a functional 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的主要原因之一是允许更容易的并行编程。


The reason you got a compiler error is that, as the error says, outside variables used in a lambda expression must be effectively final; that is, declaring them final (if they aren't already) must not change the meaning of the program, or change whether or not it compiles. Using a mutable assignment in a lambda is therefore generally forbidden, and with good reason: mutation screws up parallelization, and one of the major reasons lambdas were included in Java 8 was to allow easier parallel programming.

一般来说,每当你想以某种方式总结结果时, reduce (在其三个重载中的任何一个)都是你的首选方法。学习如何使用 map 过滤器 reduce ,以及使用 Stream s时, flatMap 非常重要。

Generally speaking, whenever you want to "sum up" results in some way, reduce (in any of its three overloads) is your go-to method. Learning how to use map, filter, reduce, and flatMap effectively is very important when working with Streams.

这篇关于lambda中的Java 8 lambda无法修改外部lambda中的变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆