在封闭范围内定义的局部变量日志必须是最终的或有效的最终

Bal*_*raj 16 java lambda java-8 apache-spark

我是lambda和Java8的新手.我正面临以下错误.

在封闭范围内定义的局部变量日志必须是最终的或有效的最终

public JavaRDD<String> modify(JavaRDD<String> filteredRdd) {

    filteredRdd.map(log -> {

        placeHolder.forEach(text -> {

            //error comes here
            log = log.replace(text, ",");

        });

        return log;

    });

    return null;
}
Run Code Online (Sandbox Code Playgroud)

Gho*_*ica 28

该消息说,到底是什么问题:你的变量数必须是最后的(即:携带关键字决赛),也可以有效地最终(即:你只有一个值分配给它一旦拉姆达外).

否则,您不能在lambda语句中使用该变量.但是,当然,这与您使用日志冲突.重点在于:你不能在lambda中写一些外在的东西......所以你必须退后一步,为你想做的事情寻找其他方法.

从这个意义上讲:只要相信编译器.


Ked*_*ade 11

这种限制的原因与Java语言特性的原因相同,即从(匿名)内部类中访问的局部变量必须(有效)最终.

rgettman的这个答案深入了解它的细节.rgettman以清晰的细节解释了这些局限性,并链接到该答案,因为lambda表达式的行为应该与匿名内部类的行为相同.请注意,对于类或实例变量,不存在此类限制.造成这种情况的主要原因有点复杂,我无法解释它比Roedy Green在这里做的更好.仅在此复制,因此它位于以下位置:

规则是匿名内部类只能访问封闭方法的最终局部变量.为什么?因为内部类的方法可以稍后调用,所以在产生它的方法终止之后很久,例如通过AWT(高级窗口工具包)事件.局部变量早已不复存在.然后,匿名类必须使用flash冻结的副本,这些副本只需要匿名内部类对象中的编译器隐藏的内容.你可能会问,为什么局部变量必须是最终的?编译器是否也可以采用非最终局部变量的副本,就像它对非最终参数的方式一样?如果它这样做,你将有两个变量副本.每个都可以独立更改,就像调用者和被调用者的参数副本一样,但是您可以使用相同的语法来访问任一副本.这会令人困惑.所以Sun坚称当地是最终的.这无关紧要,实际上有两份副本.

匿名类访问调用者的最终局部变量的能力实际上只是语法糖,用于自动传递一些局部变量作为额外的构造函数参数.对我来说,整个事情都让我觉得稀释了eau de kludge.


Deb*_*Deb 6

在某些用例中可以有解决方法。以下代码抱怨该startTime变量不是有效的最终变量:

List<Report> reportsBeforeTime = reports.stream()
                                        .filter(r->r.getTime().isAfter(startTime))
                                        .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

因此,只需将值复制到最终变量,然后再将其传递给 lambda:

final LocalTime finalStartTime = startTime;
    List<Report> reportsBeforeTime = reports.stream()
                                            .filter(r->r.getTime().isAfter(finalStartTime))
                                            .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

但是,如果您需要更改 lambda 函数内的局部变量,那么这是行不通的。


Mr.*_*r.Q 5

请记住,方法内部类不能修改其周围方法的任何值。foreach 中的第二个 lambda 表达式正在尝试访问其周围的方法变量 (log)。

要解决这个问题,您可以避免在 foreach 中使用 lambda,因此对每个简单并替换 log 中的所有值。

    filteredRdd.map(log -> {
        for (String text : placeHolder){
            log = log.replace(text,",");
        }
        return log;
    });

   
Run Code Online (Sandbox Code Playgroud)