加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

为什么java 8 lambdas允许访问非final类变量?

发布时间:2020-12-15 00:46:40 所属栏目:Java 来源:网络整理
导读:参见英文答案 Local class can access non-final variable in java 81个 Lambdas: local variables need final,instance variables don’t9个 我理解为什么编译器不接受以下内容: class Foo { public SupplierString makeSupplier() { String str = "hello"
参见英文答案 > Local class can access non-final variable in java 81个
> Lambdas: local variables need final,instance variables don’t9个
我理解为什么编译器不接受以下内容:
class Foo {
    public Supplier<String> makeSupplier() {
        String str = "hello";
        Supplier<String> supp = () -> return str;

        // gives the expected compile error because
        // str is not effectively final
        // (str is a local variable,compile-time error
        //  as per JLS 15.27.2.)
        str = "world";

        return supp;
    }
}

令我困惑的是编译器接受以下内容,并且单元测试通过:

class Bar {
    private String str = "hello";

    public void setStr(String str) {
        this.str = str;
    }

    public Supplier<String> makeSupplier() {
        Supplier<String> supp = () -> { return str; };
        return supp;
    }

    @Test 
    public void Unit_lambdaCapture() {    
        Supplier<String> supp = makeSupplier();
        Assert.assertEquals(supp.get(),"hello");
        setStr("foo");
        Assert.assertEquals(supp.get(),"foo");
    }
}

为什么上述有效且正常工作?欢迎使用JLS相关部分的指针(第15.27.2节,仅讨论局部变量).

解决方法

我们都同意第一个例子不起作用,因为局部变量或参数必须在 lambda expression body中使用 final or effectively final.

但是你的第二个例子不涉及局部变量或参数,因为str是一个实例字段. Lambda表达式可以像实例方法一样访问实例字段:

15.27.2. Lambda Body

A lambda body is either a single expression or a block (§14.2). Like a method body,a lambda body describes code that will be executed whenever an invocation occurs.

事实上,java编译器从lambda表达式中创建一个私有方法lambda $0,它只是访问实例字段str:

private java.lang.String lambda$0() {
    0 aload_0;                /* this */
    1 getfield 14;            /* .str */
    4 areturn;
}

另一种观点:您还可以使用普通的匿名内部类来实现供应商:

public Supplier<String> makeSupplier() {
    return new Supplier<String>() {
        public String get() { return str; }
    };
}

从内部类访问实例字段非常常见,而不是Java 8的专业.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读