Java的方法引用(method reference)的使用例

本文深入解析Java中的方法引用,一种简化lambda表达式的语法糖。通过详细的示例代码,阐述了方法引用的四种形式:静态方法引用、特定实例方法引用、任意实例方法引用及构造器引用。文章展示了如何在不同的函数式接口中应用这些方法引用,提高代码的可读性和简洁性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java 中的 method reference 可以理解为 lambda 表达式的简略写法。阅读此篇需要有 lambda 表达式基础。

首先引用Oracle官网的The Java™ Tutorials的表述:

You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it’s often clearer to refer to the existing method by name. Method references enable you to do this…

形式上method references分为四种:

KindExample
Reference to a static methodContainingClass::staticMethodName
Reference to an instance method of a particular objectcontainingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular typeContainingType::methodName
Reference to a constructorClassName::new

其中第三条相对较难理解,举例如下:

例如,某函数式接口的抽象方法的方法签名是int name(ClassA a, ClassB b, ClassC c),而它的实现是ClassA类的实例方法int xxx(ClassB bbb, ClassC ccc),那么用method reference写法可以写成:ClassA::xxx。具体示例代码如下。

  • 接口1~6,接收参数类型各不同
public interface MyFunctionalInterface1 {
    int onlyMethod(String a, String b);
}
public interface MyFunctionalInterface2 {
    int onlyMethod(MyPojo a, String b);
}
public interface MyFunctionalInterface3 {
    int onlyMethod(MyPojo a, String b, int c);
}
public interface MyFunctionalInterface4 {
    int onlyMethod(MyPojo a);
}
public interface MyFunctionalInterface5 {
    void onlyMethod(String a, String b);
}
public interface MyFunctionalInterface6<R> {
    R onlyMethod();
}
  • 入参类
import static com.navinfo.platform.methodref.Logger.print;

public class MyPojo {
    public int getAge() {
        print("MyPojo.getAge", "int()");
        return 0;
    }

    public int getChar(String str) {
        print("MyPojo.getChar", "int(String)");
        return 0;
    }

    public int getCharAt(String str, int i) {
        print("MyPojo.getCharAt", "int(String,int)");
        return 0;
    }
}
  • 打印日志工具类
public class Logger {
    public static void print(String method, String message) {
        System.out.printf("[%-16s] %s\n", method, message);
    }
}
  • 实现方法提供者
import static com.navinfo.platform.methodref.Logger.print;

public class MethodProviderService {
    public static int staticMethod1(String str, String str2) {
        print("staticMethod1", "int(String,String)");
        return 0;
    }

    public static int staticMethod2(MyPojo pojo, String str) {
        print("staticMethod2", "int(MyPojo,String)");
        return 0;
    }

    public int instanceMethod1(String str, String str2) {
        print("instanceMethod1", "int(String,String)");
        return 0;
    }

    public int instanceMethod2(MyPojo pojo, String str) {
        print("instanceMethod2", "int(MyPojo,String)");
        return 0;
    }

    public int instanceMethod3(MyPojo pojo, String str, int i) {
        print("instanceMethod3", "int(MyPojo,String,int)");
        return 0;
    }

    public void instanceMethod4(String str, String str2) {
        print("instanceMethod4", "void(String,String)");
    }
}
  • 测试主类
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;

import static com.navinfo.platform.methodref.Logger.print;

public class TestMethodRefMain {
    private MethodProviderService providerService = new MethodProviderService();
    private MyPojo somePojo = new MyPojo();

    public static void main(String[] args) {
        new TestMethodRefMain().run();
    }

    private void run() {
        consumeIf1(MethodProviderService::staticMethod1);
        consumeIf1(providerService::instanceMethod1);
        consumeIf1((s1, s2) -> s1.indexOf(s2));
        consumeIf1(String::indexOf);

        consumeIf2(MethodProviderService::staticMethod2);
        consumeIf2(providerService::instanceMethod2);
        consumeIf2((o, s) -> o.getChar(s));
        consumeIf2(MyPojo::getChar);

        consumeIf3(providerService::instanceMethod3);
        consumeIf3((o, s, i) -> o.getCharAt(s, i));
        consumeIf3(MyPojo::getCharAt);

        consumeIf4(o -> o.getAge());
        consumeIf4(MyPojo::getAge);

        consumeIf5(providerService::instanceMethod4);
        consumeIf5(providerService::instanceMethod1);
        consumeIf5((s1, s2) -> new Object());
        consumeIf5(Objects::<String>requireNonNull);
        consumeIf5(String::startsWith);
        consumeIf5(Arrays::asList);

        consumeIf6(ArrayList<String>::new);
    }

    private void consumeIf1(MyFunctionalInterface1 x) {
        print("consumeIf1", "接收 MyFunctionalInterface1 入参,方法签名 int(String,String)");
        x.onlyMethod("foo", "bar");
    }

    private void consumeIf2(MyFunctionalInterface2 x) {
        print("consumeIf2", "接收 MyFunctionalInterface2 入参,方法签名 int(MyPojo,String)");
        x.onlyMethod(somePojo, "foo");
    }

    private void consumeIf3(MyFunctionalInterface3 x) {
        print("consumeIf3", "接收 MyFunctionalInterface3 入参,方法签名 int(MyPojo,String,int)");
        x.onlyMethod(somePojo, "foo", 0);
    }

    private void consumeIf4(MyFunctionalInterface4 x) {
        print("consumeIf4", "接收 MyFunctionalInterface4 入参,方法签名 int(MyPojo)");
        x.onlyMethod(somePojo);
    }

    private void consumeIf5(MyFunctionalInterface5 x) {
        print("consumeIf5", "接收 MyFunctionalInterface5 入参,方法签名 void(String,String)");
        x.onlyMethod("foo", "bar");
    }

    private void consumeIf6(MyFunctionalInterface6 x) {
        print("consumeIf6", "接收 MyFunctionalInterface6 入参,方法签名 <R> R()");
        x.onlyMethod();
    }
}
  • 打印结果
[consumeIf1      ] 接收 MyFunctionalInterface1 入参,方法签名 int(String,String)
[staticMethod1   ] int(String,String)
[consumeIf1      ] 接收 MyFunctionalInterface1 入参,方法签名 int(String,String)
[instanceMethod1 ] int(String,String)
[consumeIf1      ] 接收 MyFunctionalInterface1 入参,方法签名 int(String,String)
[consumeIf1      ] 接收 MyFunctionalInterface1 入参,方法签名 int(String,String)
[consumeIf2      ] 接收 MyFunctionalInterface2 入参,方法签名 int(MyPojo,String)
[staticMethod2   ] int(MyPojo,String)
[consumeIf2      ] 接收 MyFunctionalInterface2 入参,方法签名 int(MyPojo,String)
[instanceMethod2 ] int(MyPojo,String)
[consumeIf2      ] 接收 MyFunctionalInterface2 入参,方法签名 int(MyPojo,String)
[MyPojo.getChar  ] int(String)
[consumeIf2      ] 接收 MyFunctionalInterface2 入参,方法签名 int(MyPojo,String)
[MyPojo.getChar  ] int(String)
[consumeIf3      ] 接收 MyFunctionalInterface3 入参,方法签名 int(MyPojo,String,int)
[instanceMethod3 ] int(MyPojo,String,int)
[consumeIf3      ] 接收 MyFunctionalInterface3 入参,方法签名 int(MyPojo,String,int)
[MyPojo.getCharAt] int(String,int)
[consumeIf3      ] 接收 MyFunctionalInterface3 入参,方法签名 int(MyPojo,String,int)
[MyPojo.getCharAt] int(String,int)
[consumeIf4      ] 接收 MyFunctionalInterface4 入参,方法签名 int(MyPojo)
[MyPojo.getAge   ] int()
[consumeIf4      ] 接收 MyFunctionalInterface4 入参,方法签名 int(MyPojo)
[MyPojo.getAge   ] int()
[consumeIf5      ] 接收 MyFunctionalInterface5 入参,方法签名 void(String,String)
[instanceMethod4 ] void(String,String)
[consumeIf5      ] 接收 MyFunctionalInterface5 入参,方法签名 void(String,String)
[instanceMethod1 ] int(String,String)
[consumeIf5      ] 接收 MyFunctionalInterface5 入参,方法签名 void(String,String)
[consumeIf5      ] 接收 MyFunctionalInterface5 入参,方法签名 void(String,String)
[consumeIf5      ] 接收 MyFunctionalInterface5 入参,方法签名 void(String,String)
[consumeIf5      ] 接收 MyFunctionalInterface5 入参,方法签名 void(String,String)
[consumeIf6      ] 接收 MyFunctionalInterface6 入参,方法签名 <R> R()

end

Java 8 引入了方法引用Method Reference),它是 Lambda 表达式的一种简化形式。通过方法引用,我们可以直接引用已有的类或实方法,而无需再显式地书写完整的 lambda 表达式。 ### 方法引用的基本语法 方法引用主要有以下四种形式: #### 1. **静态方法引用** 格式为 `类名::静态方法`。 -: ```java Arrays.sort(array, String::compareToIgnoreCase); ``` #### 2. **特定对象的实方法引用** 如果某个对象已经存在,并需要引用它的方法,则可以使用 `对象::实方法` 的格式。 -: ```java Consumer<String> consumer = System.out::println; consumer.accept("Hello World"); ``` #### 3. **任意类型实方法引用** 当我们需要对某类型的任意对象应用其实方法时,可以用这种模式——即 `类型::实方法` 形式。 -: ```java Function<String, Integer> function = Integer::parseInt; // 将String转成Integer int num = function.apply("123"); // 结果为123 ``` #### 4. **构造函数引用** 可用于创建新对象的场景中,其格式类似于其他方法引用的形式 `Class::new`。 -: ```java Supplier<Date> supplier = Date::new; // 创建一个新的Date对象 Date date = supplier.get(); ``` ### 使用场景及优点 - 简化代码:当lambda表达式的主体仅是对现有方法的一次简单调用时,可以直接改用更简洁的方法引用表示法; - 提高可读性:对于熟悉的标准库功能来说,使用名字代替匿名内部类会使得意图更加清晰直观; 总之,在适当的地方利用好方法引用可以使程序变得既紧凑又易于理解!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值