方法引用与构造器引用
Lambda表达式的主体只有一条语句时,程序不仅可以省略包含主体的花括号,还可以通过英文双冒号“::”的语法格式来引用方法和构造器(即构造方法),这两种形式可以进一步简化Lambda表达式的书写,其本质都是对Lambda表达式的主体部分已存在的方法进行直接引用,主要区别就是对普通方法与构造方法的引用而已。
在JDK 8中,Lambda表达式支持的引用类型主要有以下几种,如表1所示。
表1 Lambda表达式对普通方法和构造方法的引用形式
种类 | Lambda表达式示例 | 对应的引用示例 |
---|---|---|
类名引用普通方法 | (x,y,...)-> 对象名x.类普通方法名(y,...) | 类名::类普通方法名 |
类名引用静态方法 | (x,y,...) -> 类名.类静态方法名(x,y,...) | 类名::类静态方法名 |
对象名引用方法 | (x,y,...) -> 对象名.实例方法名(x,y,...) | 对象名::实例方法名 |
构造器引用 | (x,y,...) -> new 类名 (x,y,...) | 类名::new |
在了解了Lambda表达式支持的引用类型后,接下来分别通过案例对这几种引用的使用进行演示,由于这里类名引用普通方法的形式较为复杂,因此将会最后讲解。
1.类名引用静态方法
类名引用静态方法也就是通过类名对静态方法的引用,该类可以是Java自带的特殊类,也可以是自定义的普通类。接下来通过一个求绝对值的案例来演示类名(Math特殊类)引用静态方法的使用,如文件1所示。
文件1 Example24.java
1 //定义一个函数式接口
2 @FunctionalInterface
3 interface Calcable {
4 int calc(int num);
5 }
6 // 定义一个类,并在类中定义一个静态方法
7 class Math {
8 // 定义一个求绝对值方法
9 public static int abs(int num) {
10 if (num < 0) {
11 return -num;
12 } else {
13 return num;
14 }
15 }
16 }
17 // 定义测试类
18 public class Example24 {
19 private static void printAbs(int num, Calcable calcable) {
20 System.out.println(calcable.calc(num));
21 }
22 public static void main(String[] args) {
23 // 使用Lambda表达式方式
24 printAbs(-10, n -> Math.abs(n));
25 // 使用方法引用的方式
26 printAbs(-10, Math::abs);
27 }
28 }
运行结果如图1所示。
图1 运行结果
文件1中,先定义了一个函数式接口Calcable,以及一个包含静态方法的Math类,然后在测试类中编写了一个静态方法printAbs()和一个main()方法,最后在main()方法中分别使用了Lambda表达式和方法引用的方式作为静态方法printAbs()的参数进行调用。
从图1可以看出,通过Lambda表达式和类名引用静态方法的方式都可以实现程序功能,并且类名引用静态方法的实现方式显得更为简洁。
2.对象名引用方法
对象名引用方法指的是通过实例化对象的名称来对其方法进行的引用。接下来通过一个返回字符串所有字母大写的案例来演示对象名引用方法的使用,如文件2所示。
文件2 Example25.java
1 // 定义一个函数式接口
2 @FunctionalInterface
3 interface Printable{
4 void print(String str);
5 }
6 class StringUtils {
7 public void printUpperCase(String str) {
8 System.out.println(str.toUpperCase());
9 }
10 }
11 // 定义测试类
12 public class Example25 {
13 private static void printUpper(String text, Printable pt) {
14 pt.print(text);
15 }
16 public static void main(String[] args) {
17 StringUtils stu = new StringUtils();
18 // 使用Lambda表达式方式
19 printUpper("Hello", t -> stu.printUpperCase(t));
20 // 使用方法引用的方式
21 printUpper("Hello", stu::printUpperCase);
22 }
23 }
运行结果如图2所示。
图2 运行结果
文件2中,先定义了一个函数式接口Printable,以及一个包含非静态方法的StringUtils类,该类用于实现字母大写转换。然后在测试类中编写了一个静态方法printUpper()和一个main()方法,最后在main()方法中分别使用了Lambda表达式和方法引用的方式作为静态方法printUpper()的参数进行调用。
从图2可以看出,通过Lambda表达式和对象名名引用方法的方式都可以实现程序功能,并且对象名引用方法的实现方式显得更为简洁。
3.构造器引用方法
构造器引用指的是对类自带的构造器的引用。接下来通过一个构造方法获取属性的案例来演示构造器引用方法的使用,如文件3所示。
文件3 Example26.java
1 // 定义一个函数式接口
2 @FunctionalInterface
3 interface PersonBuilder {
4 Person buildPerson(String name);
5 }
6 // 定义一个Person类,并添加有参构造方法
7 class Person {
8 private String name;
9 public Person(String name) {
10 this.name = name;
11 }
12 public String getName() {
13 return name;
14 }
15 }
16 // 定义测试类
17 public class Example26 {
18 public static void printName(String name, PersonBuilder builder) {
19 System.out.println(builder.buildPerson(name).getName());
20 }
21 public static void main(String[] args) {
22 // 使用Lambda表达式方式
23 printName("赵丽颖", name -> new Person(name));
24 // 使用构造器引用的方式
25 printName("赵丽颖", Person::new);
26 }
27 }
运行结果如图3所示。
图3 运行结果
文件3中,先定义了一个函数式接口PersonBuilder以及一个包含有构造方法的类Person,然后在测试类中编写了一个静态方法printName()和一个main()方法,最后在main()方法中分别使用了Lambda表达式和构造器引用的方式作为静态方法printName()的参数进行调用。
从图3可以看出,通过Lambda表达式和构造器引用方法的方式都可以实现程序功能,并且构造器引用方法的实现方式显得更为简洁。
4.类名引用普通方法
类名引用普通方法指的是通过一个普通类的类名来对其普通方法进行的引用。接下来仍然通过一个返回字符串所有字母大写的案例来演示类名引用普通方法的使用,如文件4所示。
文件4 Example27.java
1 // 定义一个函数式接口
2 @FunctionalInterface
3 interface Printable{
4 void print(StringUtils su, String str);
5 }
6 class StringUtils {
7 public void printUpperCase(String str) {
8 System.out.println(str.toUpperCase());
9 }
10 }
11 // 定义测试类
12 public class Example27 {
13 private static void printUpper(StringUtils su, String text,
14 Printable pt) {
15 pt.print(su, text);
16 }
17 public static void main(String[] args) {
18 // 使用Lambda表达式方式
19 printUpper(new StringUtils(), "Hello",
20 (object, t) -> object.printUpperCase(t));
21 // 使用方法引用的方式
22 printUpper(new StringUtils(), "Hello",
23 StringUtils::printUpperCase);
24 }
25 }
运行结果如图4所示。
图4 运行结果
文件4中,先定义了一个函数式接口Printable以及一个包含普通方法的类StringUtils,然后在测试类中编写了一个静态方法printUpper()和一个main()方法,最后在main()方法中分别使用了Lambda表达式和方法引用的方式作为静态方法printUpper()的参数进行调用。
从图4可以看出,通过Lambda表达式和类名引用普通方法的方式都可以实现程序功能,并且类名引用普通方法的实现方式显得更为简洁。