lambda表达式传参
Lambda表达式中使用的变量需要遵循以下规则:
1、只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
2、局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
3、不允许声明一个与局部变量同名的参数或者局部变量。
下面这段代码编译器会报错:
Variable used in lambda expression should be final or effectively final
public static void main(String args[]){ List<String> dest = new ArrayList<>(); List<String> src = new ArrayList<>(Arrays.asList("01", "02", "03")); src.forEach(item -> { add(dest,item); }); dest = null; }
因为违反了第二条规则(局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义))
稍作修改,去掉对dest的修改,可以编译通过:
public static void main(String args[]){ List<String> dest = new ArrayList<>(); List<String> src = new ArrayList<>(Arrays.asList("01", "02", "03")); src.forEach(item -> { add(dest,item); }); }
通过lambda表达式,向线程中传递局部变量,并且执行相关操作:
public static void main(String args[]){ List<String> dest = new ArrayList<>(); List<String> src = new ArrayList<>(Arrays.asList("01", "02", "03")); new Thread(()->add(dest,"a")).start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(dest.size()); } private static void add(List<String>l,String item){ l.add(item); System.out.println(item); }
为啥要有上面的限定?
lambda表达式是对内部类的简化,内部类的限定相同。网上搜索了一下,觉得靠谱点的答案是:
As for why local variables used within the body of an anonymous inner class have to be final - it's to avoid confusion, as far as I can tell - and possibly to aid simplicity of implementation. It's entirely possible to design a language where variables in closures can be mutable (C# does for example), but Java's model creates an instance of the anonymous inner class with a copy of all the variables that are used within the body of the anonymous inner class. That's simple to understand (you can't observe any changes because you're not allowed to make any) and it means you don't end up with extra classes being generated just to hold variables which are used in the outer scope.
引自
翻译过来大概就是内部内创建时,它所能访问到的外部类中的各种变量都只是一份拷贝,因此为了防止你误以为能够直接修改外部类的变量,做了这样的设定。
还可以参考:
https://www.cnblogs.com/dolphin0520/p/3811445.html
当方法执行完毕,而匿名内部类的方法还没执行完毕时,这时候的局部变量还要继续使用,因此这里给内部类传的参数是一份拷贝。