lambda中的Java 8 lambda不能修改外部lambda中的变量

Pat*_*ard 5 java lambda java-8

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

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

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

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

strings.stream().map(s -> transformers.stream().forEach(t -> s = t.apply(s))).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

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

Pth*_*ame 13

使用流来执行此操作的最佳方法是使用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);
Run Code Online (Sandbox Code Playgroud)

当然,这假设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);
Run Code Online (Sandbox Code Playgroud)

你得到编译器错误的原因是,正如错误所说,lambda表达式中使用的外部变量必须是有效的 ; 也就是说,声明它们final(如果它们还没有)不得改变程序的含义,或改变它是否编译.使用在一个lambda一个可变分配,因此一般禁止的,并有很好的理由:突变螺丝了并行化,主要的原因lambda表达式的一个被列入的Java 8是为了让更容易并行编程.

一般来说,无论何时你想以某种方式"总结"结果,reduce(在其三个重载中的任何一个)都是你的首选方法.学习如何使用map,filter,reduce,和flatMap有工作的时候实际上是非常重要Stream秒.