【Java异常】Variable used in lambda expression should be final or effectively final
从字面上来理解这句话,意思是:*lambda表达式中使用的变量应该是final或者有效的final*,也就是说,lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。 要求外部变量为final是在编译期以强制手段确保用户不会在lambda表达式中做修改原变量值的操作。
其实在Java8之前,匿名类中如果要访问局部变量的话,那个局部变量必须显式的声明为final。
Demo代码示例:
package com.example.core.mydemo.java8;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Java8FinalTest {
public static void main(String[] args) {
//如果直接定义变量,不会报错”Variable used in lambda expression should be final or effectively final“
// List<Integer> number = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//如果分开赋值,就会报错”Variable used in lambda expression should be final or effectively final“
List<Integer> number = null;
number = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//创建临时中间变量,可以用final也可以不用final
final List<Integer> numberTmp = number;
//Variable used in lambda expression should be final or effectively final
List<Integer> group = Arrays.asList(1,2);
List<Object> groupResult = group.stream().map(x -> calc(numberTmp)).collect(Collectors.toList());
groupResult.stream().forEach(System.out :: println);
//匿名内部类 1.8不会报错
//1.7会报错:Variable 'jdkVersion' is accessed from within inner class, needs to be declared final,意思是:变量‘dkVersion’在匿名内部类中被访问,必须被声明为final类型的。
String jdkVersion = "1.7";
testFinal(new Suppliers(){
@Override
public String get() {
return jdkVersion;
}
});
}
public static void testFinal(Suppliers supplier){
System.out.println("supplier=" + supplier.get());
}
private static Object calc(List<Integer> number) {
//变量不允许修改
// number.add(11); Exception in thread "main" java.lang.UnsupportedOperationException
return number.stream().mapToInt(x -> x).sum();
}
static class Suppliers{
public String get(){
return "hello world";
}
}
}