1. 概述

匿名类类似于没有名称的嵌套类,而Lambda表达式是Java 8引入的,旨在推广函数式编程。在某些场景中,它们被用作匿名类的替代品。本文将探讨匿名类和Lambda表达式之间的区别。

2. 匿名内部类

匿名类实现接口和抽象类,但无需创建额外的子类。此外,匿名类没有名称,并且它在同一时间提供类定义并实例化

现在,让我们看一个实现Runnable接口的匿名类示例:

public class AnonymousClassExample{

    public static void main(String[] args){
        Thread t1 = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("Thread: "+Thread.currentThread().getName()+" started");
            }
        });
        t1.start();
    }
}

在这个例子中,我们创建了一个名为AnonymousClassExample的类,并使用匿名类实现了Runnable接口。我们没有创建单独的Runnable接口实现类。

3. Lambda表达式

Lambda表达式实现的是只有单个未实现方法的功能接口。Lambda表达式本质上是一个无名的方法定义,使得代码更简洁易读。它还提供了一种将函数作为方法参数传递的方式。

现在,让我们看看一个实现Runnable接口的Lambda表达式示例:

public class LambdaExpressionExample{

    public static void main(String[] args){
        Thread t1 = new Thread(()->System.out.println("Thread: "+Thread.currentThread().getName()+" started"));
        t1.start();
    }
}

在这里,我们使用了一个匿名方法。这将解析为Runnable接口的run()方法。

即使在功能接口的情况下,我们也完全可以使用匿名类和Lambda表达式互换。但是它们之间存在差异。现在,让我们深入探讨这些差异。

4. 匿名类与Lambda表达式的比较

如前所述,匿名类用于接口和抽象类,而Lambda表达式仅用于功能接口。让我们来看看它们之间的更多差异。

4.1. 语法

匿名类同时提供类定义并实例化。我们使用new关键字和正在实现的类或接口的名称。这就像调用构造函数,但我们还提供了方法实现并声明状态变量。匿名类是一个表达式,将其赋值给实现的类或接口的引用变量。因此,我们在末尾也添加分号。

另一方面,Lambda表达式是一个没有名称的方法。我们在功能接口的未实现方法签名中提供方法,无需提及方法参数的数据类型。方法在运行时解析。

4.2. this关键字和变量的作用域

在匿名类中,this关键字指的是匿名类本身。但在Lambda表达式中,this指的是其包含类。

我们也可以在匿名类中声明成员变量,而在Lambda表达式中则不可行。因此,匿名类可以有状态。Lambda表达式内部声明的变量作为局部变量。两者都可以访问包含类的成员变量。

4.3. 编译过程

对于每个匿名类,编译时都会生成一个单独的类文件。类文件的格式是类名后跟美元符号和一个数字。例如,在名为TestClass的类中定义匿名类时,编译后会创建一个额外的文件TestClass$1.class

另一方面,对于Lambda表达式,会在类文件中添加invokedynamic指令。这个操作码指令有助于确定应调用的功能接口方法。

当编译Lambda表达式时,会在字节码中添加一个等效的私有静态或非静态方法。这个方法的签名与功能接口方法匹配。

此外,如果使用了Lambda表达式,捕获的参数也会在方法参数列表的开头。还会添加一个额外的indy调用站点,其中包含了调用Lambda表达式生成的私有方法所需的所有信息。在运行时,调用站点被启动,并链接到的私有方法被调用。

4.4. 性能

现在让我们看看这两种方式对性能的影响。总体来说,Lambda表达式在性能上优于匿名类。这是因为匿名类会导致编译时额外生成一个类文件,这在类加载和运行时验证时会消耗更多时间。

Lambda表达式的性能更好,因为invokedynamic指令在运行时动态绑定Lambda表达式到功能接口方法。Lambda表达式的第一次调用较慢,后续调用更快。

5. 总结

在这篇文章中,我们探讨了Lambda表达式和匿名内部类之间的差异。我们了解了它们在语法、编译过程和性能方面的不同。

如往常一样,示例代码可在GitHub上找到。