前言
之前介绍了Lambda表达式是匿名内部类的一种简化,因此它可以部分取代匿名内部类的作用。
相同点
* Lambda表达式与匿名内部类一样,都可以直接访问"effectively final"的局部变量,以及外部类的成员变量。
* Lambda表达式创建的对象与匿名内部类生成的对象一样,都可以直接调用从接口中继承的默认方法。
下面程序示范了相似之处:
@FunctionalInterface
interface Displayable{
void display();
default int add(int a , int b){
return a+b;
}
}
public class LambdaAndInner {
private int age = 12;
private static String name = "软件中心";
public void test(){
String book = "effective java";
Displayable dis = () -> {
//访问 "effectively final" 的局部变量
System.out.println("book的局部变量为" + book);
//访问外部类的实例变量和类变量
System.out.println("外部类的age的实例变量为" + age);
System.out.println("外部类的name类变量为" + name);
};
dis.display();
//调用dis对象从接口中继承的add方法
System.out.println(dis.add(3,5));
}
public static void main(String[] args) {
LambdaAndInner lambda = new LambdaAndInner();
lambda.test();
}
}
上面程序使用 Lambda表达式创建了一个 Displayable的对象, Lambda表达式的代码块中的三行粗体字代码分别示范了访问“ effectively final”的局部变量、外部类的实例变量和类变量。从这点来看,Lambda表达式的代码块与匿名内部类的方法体是相同的。
与匿名内部类相似的是,由于 Lambda表达式访问了book局部变量,因此该局部变量相当于有个隐式的final修饰,因此同样不允许对book局部变量重新赋值。
不同点
* 匿名内部类可以任意接口创建实例——不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可;但 Lambda表达式只能为函数式接口创建实例。
* 匿名内部类可以为抽象类甚至普通类创建实例;但 Lambda表达式只能为函数式接口创建实例。
* 匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法;但 Lambda表达式的代码块不允许调用接口中定义的默认方法。
对于 Lambda表达式的代码块不允许调用接口中定义的默认方法的限制,可以尝试对上面的LambdaAndInner.java程序稍做修改,在 Lambda表达式的代码块中增加如下一行:
//尝试调用接口中的默认方法,编译器会报错
System.out.println(add(3,5));
虽然 Lambda表达式的目标类型: Displayable中包含了add()方法,但 Lambda表达式的代码块不允许调用这个方法;如果将上面的 Lambda表达式改为匿名内部类的写法,当匿名内部类实现 display抽象方法时,则完全可以调用这个add()方法。