Lambda表达式 笔记

Lambda表达式

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。

语法

(parameters) -> expression
//或
(parameters) ->{ statements; }

特征

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

实例

public class Java8Tester {
   public static void main(String args[]){
      Java8Tester tester = new Java8Tester();
        
      // 类型声明
      MathOperation addition = (int a, int b) -> a + b;
        
      // 不用类型声明
      MathOperation subtraction = (a, b) -> a - b;
        
      // 大括号中的返回语句
      MathOperation multiplication = (int a, int b) -> { return a * b; };
        
      // 没有大括号及返回语句
      MathOperation division = (int a, int b) -> a / b;
        
      System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
      System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
      System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));
        
      // 不用括号
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);
        
      // 用括号
      GreetingService greetService2 = (message) ->
      System.out.println("Hello " + message);
        
      greetService1.sayMessage("Runoob");
      greetService2.sayMessage("Google");
   }
    
   interface MathOperation {
      int operation(int a, int b);
   }
    
   interface GreetingService {
      void sayMessage(String message);
   }
    
   private int operate(int a, int b, MathOperation mathOperation){
      return mathOperation.operation(a, b);
   }
}

注意

Lambda 表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。在上面例子中,我们使用各种类型的Lambda表达式来定义MathOperation接口的方法。然后我们定义了sayMessage的执行。
Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。

变量作用域

lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

笔记

  • 能够使用Lambda的依据是必须有相应的函数接口(函数接口,是指内部只有一个抽象方法的接口)。这一点跟Java是强类型语言吻合,也就是说你并不能在代码的任何地方任性的写Lambda表达式。实际上Lambda的类型就是对应函数接口的类型。Lambda表达式另一个依据是类型推断机制,在上下文信息足够的情况下,编译器可以推断出参数表的类型,而不需要显式指名。
  • 我们看到Lambda表达式似乎只是为了简化匿名内部类书写,这看起来仅仅通过语法糖在编译阶段把所有的Lambda表达式替换成匿名内部类就可以了。但实时并非如此。在JVM层面,Lambda表达式和匿名内部类有着明显的差别。
    • 匿名内部类实现

    匿名内部类仍然是一个类,只是不需要程序员显示指定类名,编译器会自动为该类取名。因此如果有如下形式的代码,编译之后将会产生两个class文件

    - 进一步分析主类MainAnonymousClass.class的字节码,可发现其创建了匿名内部类的对象:
    ~~~
    // javap -c MainAnonymousClass.class
    public class MainAnonymousClass {
    ...
    public static void main(java.lang.String[]);
    Code:
    0: new #2 // class java/lang/Thread
    3: dup
    4: new #3 // class MainAnonymousClass$1 /创建内部类对象/
    7: dup
    8: invokespecial #4 // Method MainAnonymousClass$1.""😦)V
    11: invokespecial #5 // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
    14: invokevirtual #6 // Method java/lang/Thread.start:()V
    17: return
    }
    ~~~

    • Lambda表达式实现

    Lambda表达式通过invokedynamic指令实现,书写Lambda表达式不会产生新的类。如果有如下代码,编译之后只有一个class文件

    • 通过javap反编译命名,我们更能看出Lambda表达式内部表示的不同
    // javap -c -p MainLambda.class
    public class MainLambda {
      ...
      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; /*使用invokedynamic指令调用*/
           9: invokespecial #4                  // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
          12: invokevirtual #5                  // Method java/lang/Thread.start:()V
          15: return
    
    	  private static void lambda$main$0();  /*Lambda表达式被封装成主类的私有方法*/
    	    Code:
    	       0: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
    	       3: ldc           #7                  // String Lambda Thread run()
    	       5: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    	       8: return
    	}
    
posted @ 2020-10-21 11:07  xyyyn  阅读(62)  评论(0编辑  收藏  举报