包含范围的局部变量具有不同的结果

时间:2019-09-15 00:04:52

标签: java lambda double unary-operator

比较用于将双精度数加到双精度数的两种运算符类型: DoubleUnaryOperator UnaryOperator

    public void test() {
        double doub = 10.0;

        // This is OK
        DoubleUnaryOperator oo = d -> {
            return doub + d;
        };          
        // Compilation error: Local variable doub defined in an enclosing scope must be final or effectively final
        UnaryOperator<Double> o = d -> {
            return doub + d; 
        };

        doub = oo.applyAsDouble(.3);
        doub = o.apply(.3);
    }  

为什么只有 UnaryOperator 会出现编译错误( doub 不是最终的)? 如果变量声明从不更改,为什么会有不同的结果?

2 个答案:

答案 0 :(得分:0)

在我的情况下(Java12),我在DoubleUnaryOperatorUnaryOperator上都遇到了错误。

您遇到的情况是,您要用doub函数结果重新分配oo,然后再尝试在下一个运算符中使用doub

我引用的是:Difference between final and effectively final

  

非正式地,如果局部变量的初始值从未改变,则它实际上是最终的-换句话说,声明该最终变量不会导致编译失败。

所以,检查后我了解的是:

如果变量为final,则可以在lambda表达式中始终使用它,因为不可能重新分配它(存在-反射,但这是另一个主题)。

当声明的变量保持不变时,将显示effectively final变量。

如果要将oo的结果分配给新声明的变量,则应该可以在o中使用此变量。

我相信您尝试实现10.6的价值,这是示例:

double doub = 10.0;
DoubleUnaryOperator oo = d -> {
    return doub + d;
};
double ahh = oo.applyAsDouble(.3);
UnaryOperator<Double> o = d -> {
    return ahh + d;
};
System.out.println(o.apply(.3)); //The o.apply(.3) can be assigned to new variable 

任何重新分配给doubahh的操作都会导致编译错误(Java11)

答案 1 :(得分:0)

我无法复制您声明一个编译而另一个没有编译的陈述。对我来说,都不编译

  

信息:java:编译模块“ tuts”时发生错误   信息:javac 1.8.0_192用于编译Java源代码   信息:9/14/2019 8:10 PM-构建完成,出现1个错误和0   2秒849毫秒内发出警告   C:\ Users \ Philip \ Code \ tuts \ src \ test \ java \ tuts \ UnaryOperatorTest.java   错误:(13,60)java:从lambda引用的局部变量   表达必须是最终的或实际上是最终的

问题在于,您是在使用doub的lambda中创建新作用域之后,尝试在外部作用域中重新分配给doub

如果您可以在Lambda范围之外更改doub的值,则Lambda的功能将变得不确定。因此,必须将外部作用域的值声明为final或“有效地”确定最终值(这意味着您遵守规则,不要尝试在外部作用域中重新分配它们)。

如果仅将结果分配给另一个变量(在下面的示例中为result),则可以使这两种选择均起作用:

import org.junit.Assert;
import org.junit.Test;
import java.util.function.DoubleUnaryOperator;
import java.util.function.UnaryOperator;

public class UnaryOperatorTest {

    @Test
    public void testDoubleUnaryOperator() {
        double doub = 10.0;
        DoubleUnaryOperator doubleUnaryOperator = d -> d + doub;
        double result = doubleUnaryOperator.applyAsDouble(0.3);
        Assert.assertEquals(10.3, result, Double.MIN_VALUE);
    }

    @Test
    public void testUnaryOperator() {
        double doub = 10.0;
        UnaryOperator<Double> unaryOperator = d -> d + doub;
        double result = unaryOperator.apply(0.3);
        Assert.assertEquals(10.3, result, Double.MIN_VALUE);
    }

}

(编辑)我已逐字复制并粘贴了您的代码。从有问题的行号(31和36)可以看出,FunctionalInterface示例都无法在Java 8中编译: enter image description here

但是,通过分配给doub使result有效地最终可以使代码编译: enter image description here