The compiler says Lambda expression variables must be final, and I Pianbu Xin | Force program

Author | silent king

Source | CSDN blog expert

Exhibition | CSDN (ID: CSDNnews)

Occasionally, we need to modify the value of the variable in Lambda expressions, but if a direct attempt to modify it, the compiler will not turn a blind eye and a deaf ear, it warns us that: "variable used in lambda expression should be final or effectively final".

The reason for this happening is because Java specification is such a requirement:

Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression

must either be declared final or be effectively final (§4.12.4),

or a compile-time error occurs where the use is attempted.

That roughly means, Lambda expressions use to, but not the variables declared in Lambda expressions, must be declared as final or is effectively final, otherwise the compilation error occurs.

About the difference between final and effectively final, and there may be some small partners do not know, say a few words here.

 1final int a;
 2a = 1;
 3// a = 2;
 4// 由于 a 是 final 的,所以不能被重新赋值
 5
 6int b;
 7b = 1;
 8// b 此后再未更改
 9// b 就是 effectively final
10
11int c;
12c = 1;
13// c 先被赋值为 1,随后又被重新赋值为 2
14c = 2;
15// c 就不是 effectively final

Understand the difference between final and effectively final, we learned that if the limit is defined as final, it can not modify the value of a variable in Lambda expressions. That there is any good solution? Both have the compiler does not issue a warning, but also to modify the value of a variable.

After thinking it over, try to try, I finally found three possible solutions:

1) The limit variable declared as static.

2) The limit variable declared as AtomicInteger.

3) using an array.

Here we introduce one by one in detail.

The limit variable declared as static

要想把 limit 变量声明为 static,就必须将 limit 变量放在 main() 方法外部,因为 main() 方法本身是 static 的。完整的代码示例如下所示。

 1public class ModifyVariable2StaticInsideLambda {
 2    static int limit = 10;
 3    public static void main(String[] args) {
 4        Runnable r = () -> {
 5            limit = 5;
 6            for (int i = 0; i < limit; i++) {
 7                System.out.println(i);
 8            }
 9        };
10        new Thread(r).start();
11    }
12}

来看一下程序输出的结果:

10
21
32
43
54

OK,该方案是可行的。

把 limit 变量声明为 AtomicInteger

AtomicInteger 可以确保 int 值的修改是原子性的,可以使用 set() 方法设置一个新的 int 值,get() 方法获取当前的 int 值。

 1public class ModifyVariable2AtomicInsideLambda {
 2    public static void main(String[] args) {
 3        final AtomicInteger limit = new AtomicInteger(10);
 4        Runnable r = () -> {
 5            limit.set(5);
 6            for (int i = 0; i < limit.get(); i++) {
 7                System.out.println(i);
 8            }
 9        };
10        new Thread(r).start();
11    }
12}

来看一下程序输出的结果:

10
21
32
43
54

OK,该方案也是可行的。

使用数组

使用数组的方式略带一些欺骗的性质,在声明数组的时候设置为 final,但更改 int 的值时却修改的是数组的一个元素。

 1public class ModifyVariable2ArrayInsideLambda {
 2    public static void main(String[] args) {
 3        final int [] limits = {10};
 4        Runnable r = () -> {
 5            limits[0] = 5;
 6            for (int i = 0; i < limits[0]; i++) {
 7                System.out.println(i);
 8            }
 9        };
10        new Thread(r).start();
11    }
12}

来看一下程序输出的结果:

10
21
32
43
54

OK,该方案也是可行的。

好了,亲爱的读者朋友,以上就是本文的全部内容了,是不是感觉挺有意思的,编译器告诉我们要用 final 修饰 Lambda 表达式外的变量,但我们却找到了其他的解决方案,还一找就是 3 个,是不是感觉技能包又升级了,有没有?伸出小手给自己点个赞????吧。

PS:本篇文章中的示例代码已经同步到码云,传送门

https://gitee.com/qing_gee/JavaPoint/tree/master

原文链接:

https://blog.csdn.net/qing_gee/article/details/104438986

【End】

《原力计划【第二季】- 学习力挑战》

正式开始

即日起至 3月21日

千万流量支持原创作者

更有专属【勋章】等你来挑战

推荐阅读 

近一半程序员单身、年薪低于 15 万,程序员扎心现状大调查!

被高估了的测试驱动开发?

大脑芯片公司Neuralink计划在人脑内植入芯片,他们到底想干什么?

Java 老矣,尚能饭否?2020 Java 生态系统报告出炉

Spark大数据分布式机器学习处理实战 | 博文精选

耕技术,与实践赛跑:一文告诉你如何稳妥快速完善区块链技术并有序推动商用?

你点的每一个在看,我认真当成了喜欢

发布了1758 篇原创文章 · 获赞 4万+ · 访问量 1593万+

Guess you like

Origin blog.csdn.net/csdnnews/article/details/104604336