Java 8 effectively final

首先,看以下代码:

public static void main(String[] args) {
    int a = 1;
    int b = 2;
    b = 3;
    Runnable runnable = ()->{
        System.out.println(a);
        System.out.println(b); //此行报错。
    };
}

其中 pintln(b) 那行报错,报错信息如下:

Variable used in lambda expression should be final or effectively final

意思就是说在 lambda 表达式中使用的变量应为 final 或 effectively final。

之所以报这个错是因为Java规定:内部类或lambda表达式中使用的外部的局部变量,必须由final修饰。

那么println(a)那行为什么没有报错呢,这是因为Java8的新特性:effectively final(事实final),即未被改变过值的变量将被认定为事实上的final变量,而无需显性的用final进行修饰。

思考: 为什么Java要规定内部类或lambda表达式中使用的外部局部变量必须由final修饰。

因为Java中的局部变量是储存在栈中的,一旦方法执行完毕,局部变量就会被释放。那么,假如我们使用匿名内部类的方式或lambda表达式的方式创建了一个线程,并且在run方法中使用了外部方法的局部变量,这就可能造成外部方法已经执行完毕,局部变量已经释放,而线程却还在执行,还需要引用外部方法的局部变量。

所以,实际上内部类或lambda表达式中并不是直接引用外部方法的局部变量,而是复制了一个副本。

这种情况下,如果不加final修饰的限制的话,就可能造成,外部方法在后续的代码中已经改变了该局部变量的值,而内部类中使用的却还是原先值的副本,这在逻辑上显然是比较混乱的。

发布了16 篇原创文章 · 获赞 58 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42808551/article/details/103839006
今日推荐