在 Lambda 表达式中,如果我们的 Lambda 表达式仅仅拥有一个已经实现的方法。例如,按钮(Button)点击时打印 event 对象信息,如下:
button.setOnAction(event -> System.out.println(event));
为了追求代码简洁,Lambda 表达式提供了一种更简单的写法,通过 “::” 符号引用方法,如下:
button.setOnAction(System.out::println);
上面代码中,表达式 System.out::println 是一个方法引用,等同于 Lambda 表达式 “event ->System.out.println(event)”。
我们再举另外一个例子,假设你希望不区分大小写地对字符串进行排序,那么可以传入下面这个方法引用:
String[] strings = {"A", "C", "D", "B"}; Arrays.sort(strings, String::compareToIgnoreCase);
Lambda 方法引用使用一种简洁的方式来引用已存在的方法,可以在函数式编程中使用。它可以用来传递方法作为参数,或者在流式操作中使用。Lambda 方法引用使用双冒号(::)操作符来引用已存在的方法,”::“ 操作符将方法名和对象或类的名字分隔开来。主要有如下三种方式:
对象::实例方法,例如:System.out::println 等同于 System.out.println(x)
类::静态方法,例如:Math::pow 等同于 (x,y )-> Math.pow(x, y)
类::实例方法,例如:String::compareToIgnoreCase 等同于 (x, y) -> x.compareToIgnoreCase(y)
this::实例方法,例如:this::equals 等同于 x ->this.equals(x)
super::实例方法,例如:super::equals 等同于 x -> super.equals(x)
注意:如果有多个同名的重载方法,编译器会试图从上下文中找到最匹配的一个方法。例如,有两个版本的 Math.max 方法,一个接收 int 作为参数,而另一个接收 double 类型的值。究竟会选择哪一个方法,取决于 Math.max 被转换为的函数式接口的方法参数。同 Lambda 表达式类似,方法引用也不会独立存在,它们经常被用于转换为函数式接口的实例。
用于引用对象上的实例方法,下面将引用当前示例中的 sort 实例方法,如下:
package com.hxstrive.jdk8.lambda; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class Demo06 { public static void main(String[] args) { Demo06 demo = new Demo06(); List<String> list = Stream.of("One", "Two", "Three") // 引用对象的实例方法 .map(demo::sort) .collect(Collectors.toList()); for(String str : list) { System.out.println(str); } } private String sort(String str) { char[] chars = str.toCharArray(); Arrays.sort(chars); return new String(chars); } }
运行示例,输出如下:
Oen Tow Teehr
用于引用类上面的静态方法,下面实例将引用自定义 MyStr 类中的 sort 静态方法,如下:
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class Demo06 { public static void main(String[] args) { List<String> list = Stream.of("One", "Two", "Three") .map(MyStr::sort) // 应用静态方法 .collect(Collectors.toList()); for(String str : list) { System.out.println(str); } } } class MyStr { // 静态方法,对字符串按字符排序 public static String sort(String str) { char[] chars = str.toCharArray(); Arrays.sort(chars); return new String(chars); } }
运行示例,输出如下:
Oen Tow Teehr
用于引用类上面的实例方法,下面实例将引用 String 类的 toLowerCase 方法,如下:
import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class Demo06 { public static void main(String[] args) { List<String> list = Stream.of("One", "Two", "Three") .map(String::toLowerCase) // 引用类的实例方法 .collect(Collectors.toList()); for(String str : list) { System.out.println(str); } } }
运行示例,输出如下:
one two three
下面演示通过 this 引用本类上的 convert 实例方法,如下:
package com.hxstrive.jdk8.method_ref; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * “this::实例方法” 使用方式 * @author hxstrive.com */ public class MethodRef04 { public static void main(String[] args) { new MethodRef04(); } public MethodRef04() { List<String> list = Stream.of("Hello", "World") // 使用 this 的方式引用当前实例的 convert 方法 .map(this::convert) .collect(Collectors.toList()); for(String str : list) { System.out.println(str); } } private String convert(String str) { return "[" + str.toUpperCase() + "]"; } }
运行示例,输出如下:
[HELLO] [WORLD]
下面演示通过 super 引用父类上的 convert 实例方法,如下:
package com.hxstrive.jdk8.method_ref; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * “super::实例方法” 使用方式 * @author hxstrive.com */ public class MethodRef05 extends MethodRef05Super { public static void main(String[] args) { new MethodRef05(); } public MethodRef05() { List<String> list = Stream.of("Hello", "World") // 使用 super 的方式引用父类的 convert 方法 .map(super::convert) .collect(Collectors.toList()); for(String str : list) { System.out.println(str); } } } class MethodRef05Super { public String convert(String str) { return "[" + str.toUpperCase() + "]"; } }
运行示例,输出如下:
[HELLO] [WORLD]