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