(转)Java 8:一文掌握 Lambda 表达式

2022/7/31 1:25:58

本文主要是介绍(转)Java 8:一文掌握 Lambda 表达式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

原文:https://zhuanlan.zhihu.com/p/90815478

 

List list = function.apply(10);

使用 Lambda 表达式,我们一般可以这样写:

Function<Integer, ArrayList> function = n -> new ArrayList(n);

使用「引用构造方法」的方式,我们可以简写成这样:

Function<Integer, ArrayList> function = ArrayList::new;

4. 自定义函数接口

自定义函数接口很容易,只需要编写一个只有一个抽象方法的接口即可,示例代码:

@FunctionalInterface
public interface MyInterface<T> {
    void function(T t);
}

上面代码中的 @FunctionalInterface 是可选的,但加上该注解编译器会帮你检查接口是否符合函数接口规范。就像加入 @Override 注解会检查是否重写了函数一样。

5. 实现原理

经过上面的介绍,我们看到 Lambda 表达式只是为了简化匿名内部类书写,看起来似乎在编译阶段把所有的 Lambda 表达式替换成匿名内部类就可以了。但实际情况并非如此,在 JVM 层面,Lambda 表达式和匿名内部类其实有着明显的差别。

5.1 匿名内部类的实现

匿名内部类仍然是一个类,只是不需要我们显式指定类名,编译器会自动为该类取名。比如有如下形式的代码:

public class LambdaTest {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World");
            }
        }).start();
    }
}

编译之后将会产生两个 class 文件:

LambdaTest.class
LambdaTest$1.class

使用 javap -c LambdaTest.class 进一步分析 LambdaTest.class 的字节码,部分结果如下:

public static void main(java.lang.String[]);
  Code:
     0: new           #2                  // class java/lang/Thread
     3: dup
     4: new           #3                  // class com/example/myapplication/lambda/LambdaTest$1
     7: dup
     8: invokespecial #4                  // Method com/example/myapplication/lambda/LambdaTest$1."<init>":()V
    11: invokespecial #5                  // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
    14: invokevirtual #6                  // Method java/lang/Thread.start:()V
    17: return

可以发现在 4: new #3 这一行创建了匿名内部类的对象。

5.2 Lambda 表达式的实现

接下来我们将上面的示例代码使用 Lambda 表达式实现,代码如下:

public class LambdaTest {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("Hello World")).start();
    }
}

此时编译后只会产生一个文件 LambdaTest.class,再来看看通过 javap 对该文件反编译后的结果:

public static void main(java.lang.String[]);
  Code:
     0: new           #2                  // class java/lang/Thread
     3: dup
     4: invokedynamic #3,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
     9: invokespecial #4                  // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
    12: invokevirtual #5                  // Method java/lang/Thread.start:()V
    15: return

从上面的结果我们发现 Lambda 表达式被封装成了主类的一个私有方法,并通过 invokedynamic 指令进行调用。

因此,我们可以得出结论:Lambda 表达式是通过 invokedynamic 指令实现的,并且书写 Lambda 表达式不会产生新的类。

既然 Lambda 表达式不会创建匿名内部类,那么在 Lambda 表达式中使用 this 关键字时,其指向的是外部类的引用。

6. 优缺点

优点:

  • 可以减少代码的书写,减少匿名内部类的创建,节省内存占用。
  • 使用时不用去记忆所使用的接口和抽象函数。

缺点:

  • 易读性较差,阅读代码的人需要熟悉 Lambda 表达式和抽象函数中参数的类型。
  • 不方便进行调试。


这篇关于(转)Java 8:一文掌握 Lambda 表达式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程