方法引用method reference
写在前面
我们已经知道,lambda表达式是一个匿名函数,可以用lambda表达式来实现一个函数式接口。
很自然的,我们会想到类的方法也是函数,本质上和lambda表达式是一样的,那是否也可以用类的方法来实现一个函数式接口呢?答案是可以的。我们称之为方法引用(method reference)。
方法引用
一个典型例子,向一个Map中写入单词以及它的长度:
1 | public static void simpleMethodReference() { |
上述代码中,String::length 就是方法引用,它用 :: 来分割类名或对象与方法名,:: 左侧是类名或对象,:: 右侧是方法名。
一般来说,方法引用有4种情况:
-
object::instanceMethod —— 对象 + 实例方法
-
Class::staticMethod —— 类名 + 静态方法
-
Class::instanceMethod —— 类名 + 实例方法
-
Class::new —— 类名 + 关键字 new ,这种情况又称为构造器引用(constructor reference)
1. object::instanceMethod
object::instanceMethod,:: 左侧是一个对象,:: 右侧是实例方法名。
它等价于提供了 instanceMethod 方法的参数列表的 lambda表达式。
形象来说,假设方法 instanceMethod 的参数列表为 (x, y),那么 object::instanceMethod 等价于 (x, y) -> object.instanceMethod(x, y) 。
例如对于字符串 str (String str = “”):
str::compareTo 等价于 s -> str.compareTo(s)
示例代码如下:
1 | public static void objectInstanceMethodReference() { |
上述代码的输出是:
{him=5, you=-12}
2. Class::staticMethod
Class::staticMethod,:: 左侧是一个类,:: 右侧是静态方法名。
它等价于提供了staticMethod方法的参数列表的lambda表达式。
形象来说,假设静态方法 staticMethod 的参数列表为 (x, y),那么 Class::staticMethod 等价于 (x, y) -> Class.staticMethod(x, y) 。
例如:
System.out::println 等价于 x -> System.out.print(x)
示例代码:
1 | public static void classStaticMethodReference() { |
上述代码输出为:
Guangdong
Zhejiang
Jiangsu
3. Class::instanceMethod
对于Class::instanceMethod,:: 左侧是一个类,:: 右侧是实例方法名。
假设 instanceMethod 的参数列表是 (x, y),那么Class::instanceMethod 等价于lambda表达式 (obj, x, y) -> obj.instanceMethod(x, y),其中 obj 是 Class 的对象实例。
例如:
String::length 等价于 s -> s.length()
String::compareToIgnoreCase 等价于 (s1, s2) -> s1.compareToIgnoreCase(s2)
示例代码:
1 | public static void classInstanceMethodReference() { |
上述代码输出为:
{hello=5}
4. Class::new
对于Class::new,new的含义是指Class的构造函数,所以又称为构造器引用(constructor reference)。
假设Class的构造函数有两个,它们的参数列表分别是(x)和(x, y),那么 Class::new 可能等价于 x -> new Class(x),也有可能等价于 (x, y) -> new Class(x, y),具体是哪个,编译器会在编译阶段通过上下文推断出来。
例如:
BigDecimal::new ,根据上下文,可能等价于 (String s) -> new BigDecimal(s)
特别的,数组类型也可以使用构造器引用。数组类型只有一个构造参数,表示数组的长度:
String[]::new 等价于 x -> new String[x]
示例代码:
1 | public static void ctorMethodReference() { |
上述代码的输出为:
[1.1, 2.2, 3.3]
1.1
2.2
3.3
5. this::instanceMethod和super::instanceMethod
对于this::instanceMethod,很容易理解,相当于把this关键字看做是当前类的实例对象即可。
例如:
this::equals 等价于 x -> this.equals(x)
对于super::instanceMethod,会相对复杂一些,相当于在this对象上,调用的指定方法父类版本。
示例代码:
1 | public class SuperMethodReferenceExample { |
上述代码的输出为:
Hello, man!
结语
方法引用可以视为lambda表达式的一个语法糖。