Java Lambda 表达式(四):方法引用(Method Reference)
什么是方法引用
我们已在前面的 Java Lambda 表达式(一):入门一文中说过,可以使用 Lambda 表达式来创建匿名方法。但是,某些情况下,我们的 Lambda 表达式可能仅用来调用现有方法而不做任何其它事情。此时,我们可以使用方法引用来调用方法,这可使代码更加清楚和易于阅读。
-
方法引用
- 通过方法的名字来引用现有的方法,它是更加紧凑,易于阅读的 Lambda 表达式。
为了便于理解,我们创建了如下类:
package com.wuxianjiezh.test;
public class MethodReferenceTest {
public interface Say {
void run();
}
public void invoke(Say say) {
say.run();
}
public static void main(String[] args) {
MethodReferenceTest test = new MethodReferenceTest();
test.invoke(new SayHello()); // 接口实现类
test.invoke(() -> System.out.println("Hello")); // Lambda 表达式
test.invoke(new SayHello()::run); // 方法引用
}
}
class SayHello implements MethodReferenceTest.Say {
@Override
public void run() {
System.out.println("Hello");
}
}
上面的代码,分别展示了通过接口实现类、Lambda 表达式和方法引用来实现完全相同的方法调用。其中 new SayHello()::run
代表引用 SayHello
实例对象的 run
方法。
请思考一下,如果将上面的方法引用写成 test.invoke(SayHello::new)
,此时会怎么样?是否还有结果输出呢?
。。。
开始揭晓答案:没有任何结果输出。这是为啥?
。。。
我们使用以下代码来进行说明:
package com.wuxianjiezh.test;
public class MethodReferenceTest {
public interface Say {
void run();
}
public void invoke(Say say) {
System.out.println(say.getClass().getName());
say.run();
say.run();
}
public static void main(String[] args) {
MethodReferenceTest test = new MethodReferenceTest();
test.invoke(new SayHello()::run); // 引用 `SayHello` 实例对象的 `run` 方法
System.out.println("\n-----------\n");
test.invoke(SayHello::new); // 引用构造函数
}
}
class SayHello implements MethodReferenceTest.Say {
public SayHello() {
System.out.println("SayHello 构造方法");
}
@Override
public void run() {
System.out.println("Hello");
}
}
上面代码的输出结果为:
SayHello 构造方法
com.wuxianjiezh.test.MethodReferenceTest$$Lambda$1/1225358173
Hello
Hello
-----------
com.wuxianjiezh.test.MethodReferenceTest$$Lambda$2/2121055098
SayHello 构造方法
SayHello 构造方法
我们可以从以上的测试代码中发现,SayHello::new
引用的是构造函数(貌似是废话),因此就算我们调用的是 run
方法,实际上最后运行的还是构造函数。
方法引用的种类
方法引用可以分为以下几种:
- 引用静态方法。例如:
ContainingClass::staticMethodName
- 引用特定对象的实例方法。例如:
containingObject::instanceMethodName
- 引用构造函数。例如:
ClassName::new
- 引用特定类型的任意对象的实例方法。例如:
ContainingType::methodName
引用静态方法
package com.wuxianjiezh.test;
import java.util.function.Consumer;
public class MethodReferenceTest {
private String name = "Jason Wu";
public void invoke(Consumer<String> consumer) {
consumer.accept(name);
}
public static void showName(String name) {
System.out.println("我的名字是:" + name);
}
public static void main(String[] args) {
MethodReferenceTest test = new MethodReferenceTest();
test.invoke(MethodReferenceTest::showName); // 引用静态方法
}
}
引用特定对象的实例方法
package com.wuxianjiezh.test;
import java.util.function.Consumer;
public class MethodReferenceTest {
private String name = "Jason Wu";
public void invoke(Consumer<String> consumer) {
consumer.accept(name);
}
public void showName(String name) {
System.out.println("我的名字是:" + name);
}
public static void main(String[] args) {
MethodReferenceTest test = new MethodReferenceTest();
test.invoke(test::showName); // 引用特定对象的实例方法
}
}
引用构造函数
package com.wuxianjiezh.test;
import java.util.function.Supplier;
public class MethodReferenceTest {
private String name = "Jason Wu";
public MethodReferenceTest() {
}
public void invoke(Supplier<MethodReferenceTest> supplier) {
MethodReferenceTest test = supplier.get();
test.showName(name);
}
public void showName(String name) {
System.out.println("我的名字是:" + name);
}
public static void main(String[] args) {
MethodReferenceTest test = new MethodReferenceTest();
test.invoke(MethodReferenceTest::new); // 引用构造函数
}
}
引用特定类型的任意对象的实例方法
package com.wuxianjiezh.test;
import java.util.Arrays;
public class MethodReferenceTest {
public static void main(String[] args) {
String[] array = {"B", "a", "D", "f", "c", "E"};
Arrays.sort(array, String::compareToIgnoreCase); // 引用特定类型的任意对象的实例方法
Arrays.stream(array)
.forEach(System.out::println);
}
}