【函数式编程】方法引用

方法引用

什么是方法引用

  1. 方法引用是Lambda表达式的一种特殊形式。
  2. 方法引用提供了一种更简洁的方式来为Lambda参数指定现有的方法或构造器。
  3. 方法引用需要一个与现有方法声明兼容的函数式接口。
  4. 方法引用语法为:Classname::methodName

使用方法引用

举个例子就懂了,使用已经存在的方法去替换我们的Lambda表达式。

一般函数表达式写法:

csharp 复制代码
public class MyClass{
    public static void main(String[] args) {
        addMethod(5,6,(a,b) -> a+b);
    }
    public static int addMethod(int a, int b, MyFunction myFunction){
        return myFunction.add(a,b);
    }
}
@FunctionalInterface
interface MyFunction {
    int add(int a, int b);
}

使用方法引用:

csharp 复制代码
public class MyClass{
    public static void main(String[] args) {
        addMethod(5,6, Integer::sum);
    }
    public static int addMethod(int a, int b, MyFunction myFunction){
        return myFunction.add(a,b);
    }
}
@FunctionalInterface
interface MyFunction {
    int add(int a, int b);
}

可以看到: 我的函数式表达式(a,b) -> return a+b替换为Integer::sum, 把代码拷贝下来跑一跑。

为什么可以这样替换呢?

因为它们的逻辑与方法相同(Integer的sum函数是求和,而我的函数式接口也是求和,方法的逻辑相同,参数列表也相同),就可以直接替换。

Integer类的sum方法:

arduino 复制代码
public static int sum(int a, int b) {
    return a + b;
}

是不是和我的add方法一模一样呢。

方法引用的好处

那替换有什么好处呢?

  • 更简洁 - 不需要具体参数列表
  • 更易读 - 方法名直接说明功能
  • 代码复用 - 使用已经存在的函数,不用自己再去构造,效率肯定比自己写更高

方法引用的主要形式包括:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法
  • 类构造器::new
  • 数组类型[]::new

下面对四种形式进行举例子

对象::实例方法

创建类的实例,再去使用它的方法

typescript 复制代码
public class MyClass{
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.test();
    }
    public void test(){
        // 创建实例
        Cat cat = new Cat();
        // 定义消费者接口
        Consumer<String> cs1 = (s) -> System.out.println("cat eat " + s);
        Consumer<String> cs2 = cat::eat;
        // 调用方法
        cs1.accept("fish");
        cs2.accept("fish");
    }
}
class Cat{
    public void eat(String s){
        System.out.println("cat eat " + s);
    }
}

类::静态方法

直接使用类的静态方法

typescript 复制代码
public class MyClass{
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.test();
    }
    public void test(){
        // 定义消费者接口
        Consumer<String> cs1 = (s) -> System.out.println("cat eat " + s);
        Consumer<String> cs2 = Cat::eat;
        // 调用方法
        cs1.accept("fish");
        cs2.accept("fish");
    }
}
class Cat{
    public static void eat(String s){
        System.out.println("cat eat " + s);
    }
}

类::实例方法

ini 复制代码
// 方法引用-类名::实例方法名
BiFunction<String, String, Boolean> fun1 = (str1, str2) -> str1.equals(str2);
BiFunction<String, String, Boolean> fun2 = String::equals;
Boolean result2 = fun2.apply("hello", "world");
System.out.println(result2);

这个只能使用JavaJDK已经编写好的类的函数,自己编写的函数需要设为static。

类构造器::new

typescript 复制代码
public class Solution {
    public static void main(String[] args) {
        // 使用lambda表达式
        Function<String, Cat> f1 = (s)-> new Cat(s);
        Cat c1 = f1.apply("小白");
        System.out.println(c1.getName());
        // 使用方法引用
        Function<String, Cat> f2 = Cat::new;
        Cat c2 = f2.apply("小黑");
        System.out.println(c2.getName());
    }
}
class Cat{
    private String name;
    Cat(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}

注意: 使用的时候传入的参数列表需要和构造函数相匹配。比如我里面用的Fuction接口,刚刚好就是我们Cat类的对应形式,构造函数返回值为它的类对象

如果要匹配多个参数怎么办???

答案是我们自己定义函数接口呗,比如定义一个接收三个参数的:

scss 复制代码
@FunctionalInterface
interface CatFactory<T,V,R>{
    Cat getCat(T a1, V a2, R a3);
}

数组类型[]::new

typescript 复制代码
public class Solution {
    public static void main(String[] args) {
       ArrayFactory<String> af = String[]::new;
        String[] strings = af.create(5);
    }
}
@FunctionalInterface
interface ArrayFactory<T> {
    T[] create(int size);
}
相关推荐
lizhongxuan几秒前
AIOPS 的自治运维与可验证进化机制
后端
Warson_L3 小时前
python - set/tuple/dict quiz
后端
IT_Octopus4 小时前
Spring Boot 实战:@PostConstruct + Caffeine 缓存初始化与定时刷新
spring boot·后端·缓存
swipe4 小时前
从本地开发到生产部署:用 Docker Compose 跑通 NestJS、MySQL 与 Milvus
后端·langchain·llm
码事漫谈4 小时前
SenseNova Skills Studio:为商汤SenseNova U1打造的本地办公技能包
后端
zhangxingchao4 小时前
AI应用开发七:可以替代 RAG 的技术
前端·人工智能·后端
excel5 小时前
🧠 Prisma 表名大写 vs SQL 导出小写问题深度解析(附踩坑与解决方案)
前端·后端
GetcharZp6 小时前
Hermes Agent:一个真正“会成长”的开源 AI Agent,正在改变 AI 自动化玩法
后端
Gopher_HBo6 小时前
Go依赖管理
后端
ltl7 小时前
Layer Normalization:为什么 Transformer 用 LN,不用 BN
后端