publicstaticvoidmain(String[] args) {int limit =10;Runnable r = () -> { limit =5;for (int i =0; i < limit; i++)System.out.println(i); };}
和匿名内部类一样,不要在 Lambda 表达式主体内对方法内的局部变量进行修改,否则编译也不会通过:Lambda 表达式中要用到的,但又未在 Lambda 表达式中声明的变量,必须声明为 final 或者是 effectively final,否则就会出现编译错误
关于 final 和 effectively final 的区别:
finalint a;a =1;// a = 2;// 由于 a 是 final 的,所以不能被重新赋值int b;b =1;// b 此后再未更改// b 就是 effectively finalint c;c =1;// c 先被赋值为 1,随后又被重新赋值为 2c =2;// c 就不是 effectively final
那哪些情况可以修改呢?
static 变量可以在 static 方法中的 Lambda 表达式中修改:
publicclassModifyVariable2StaticInsideLambda {staticint limit =10;publicstaticvoidmain(String[] args) {Runnable r = () -> { limit =5;for (int i =0; i < limit; i++) {System.out.println(i); } };newThread(r).start(); }}
把 limit 变量声明为 AtomicInteger:AtomicInteger 可以确保 int 值的修改是原子性的,可以使用 set() 方法设置一个新的 int 值,get() 方法获取当前的 int 值。
publicclassModifyVariable2AtomicInsideLambda {publicstaticvoidmain(String[] args) {finalAtomicInteger limit =newAtomicInteger(10);Runnable r = () -> {limit.set(5);for (int i =0; i <limit.get(); i++) {System.out.println(i); } };newThread(r).start(); }}
使用数组的方式略带一些欺骗的性质,在声明数组的时候设置为 final,但更改 int 的值时却修改的是数组的一个元素:
publicclassModifyVariable2ArrayInsideLambda {publicstaticvoidmain(String[] args) {finalint [] limits = {10};Runnable r = () -> { limits[0] =5;for (int i =0; i < limits[0]; i++) {System.out.println(i); } };newThread(r).start(); }}
Lambda 和 this 关键字
Lambda 表达式并不会引入新的作用域,这一点和匿名内部类是不同的。也就是说,Lambda 表达式主体内使用的 this 关键字和其所在的类实例相同。