Java Lambda 表达式(四):方法引用(Method Reference)

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);
    }
}

你可能感兴趣的:(Java)