Java重温学习笔记,Java8新特性:Lambda 表达式

Lambda 表达式,也称闭包,它允许把函数作为一个方法的参数。使用 Lambda 表达式可以使代码更加简洁。在 Java 8 以前,若我们想要把某些功能传递给某些方法,总要去写匿名类。现在用Lambda 表达式,即可以很好地解决问题。

一、lambda 表达式的语法格式及示范:

语法:

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

示范:

(int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 };

说明:

  • Lambda 表达式可以具有零个,一个或多个参数。
  • 可以显式声明参数的类型,也可以由编译器根据上下文推断。例如 (int a) 与 (a)等同。
  • 参数用小括号括起来,用逗号分隔。例如 (a, b) 或 (int a, int b) 或 (String a, int b, float c)。
  • 空括号用于表示一组空的参数。例如 () -> 42。
  • 当有且仅有一个参数时,如果不显式指明类型,则不必使用小括号。例如 a -> return a*a。
  • Lambda 表达式的正文可以包含零条,一条或多条语句。
  • 如果 Lambda 表达式的正文只有一条语句,则大括号可不用写,且表达式的返回值类型要与匿名函数的返回类型相同。
  • 如果 Lambda 表达式的正文有一条以上的语句,则必须包含在大括号(代码块)中,且表达式的返回值类型要与匿名函数的返回类型相同。

二、一个完整的示范

public class MyDemo {
   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);
   }
   
   public static void main(String args[]) {
      MyDemo tester = new MyDemo();
        
      // 类型声明
      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");
   }
}

输出如下:

%JAVA_HOME%\bin\java "MyDemo" ...
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Runoob
Hello Google

三、从 Lambda 表达式到双冒号操作符

使用 Lambda 表达式,可以让代码变得非常简洁。例如,要创建一个比较器,以下语法就足够了:

Comparator c = (Person p1, Person p2) -> p1.getAge().compareTo(p2.getAge());

然后,使用类型推断,可以写成如下形式:

Comparator c = (p1, p2) -> p1.getAge().compareTo(p2.getAge());

更进一步,可以用如下写法:

Comparator c = Comparator.comparing(Person::getAge);

双冒号(::)操作符是 Java 中的方法引用。 当们使用一个方法的引用时,目标引用放在 :: 之前,目标引用提供的方法名称放在 :: 之后。

 四、更多Lambda 表达式的例子

1. 线程初始化

// Old way
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello world");
    }
}).start();

// New way
new Thread(
    () -> System.out.println("Hello world")
).start();

2. 事件处理

// Old way
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Hello world");
    }
});

// New way
button.addActionListener( (e) -> {
        System.out.println("Hello world");
});

3. 遍历输出(方法引用)

import java.util.*;

public class MyDemo {
 
   public static void main(String args[]) {
        // Old way
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
        for (Integer n : list) {
            System.out.print(n + " ");
        }
        System.out.println();

        // 使用 -> 的 Lambda 表达式
        list.forEach(n -> System.out.print(n + " "));
        System.out.println();

        // 使用 :: 的 Lambda 表达式
        list.forEach(System.out::print);
   }
}

4. 逻辑操作

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class MyDemo {
    public static void evaluate(List<Integer> list, Predicate<Integer> predicate) {
        for (Integer n : list) {
            if (predicate.test(n)) {
                System.out.print(n + " ");
            }
        }
        System.out.println();
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        System.out.print("输出所有数字:");
        evaluate(list, (n) -> true);

        System.out.print("不输出:");
        evaluate(list, (n) -> false);

        System.out.print("输出偶数:");
        evaluate(list, (n) -> n % 2 == 0);

        System.out.print("输出奇数:");
        evaluate(list, (n) -> n % 2 == 1);

        System.out.print("输出大于 5 的数字:");
        evaluate(list, (n) -> n > 5);
    }

}

4. Stream API 示例

// Old way
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
for(Integer n : list) {
    int x = n * n;
    System.out.println(x);
}

// New way
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
list.stream().map((x) -> x*x).forEach(System.out::println);

五、Lambda 表达式和匿名类之间的区别

  • this 关键字。对于匿名类 this 关键字解析为匿名类,而对于 Lambda 表达式,this 关键字解析为包含写入 Lambda 的类。
  • 编译方式。Java 编译器编译 Lambda 表达式时,会将其转换为类的私有方法,再进行动态绑定。

本文参考:

https://www.runoob.com/java/java8-lambda-expressions.html

https://segmentfault.com/a/1190000009186509

posted @ 2021-06-23 07:33  那些年的事儿  阅读(445)  评论(0编辑  收藏  举报