【函数式编程】方法引用

方法引用

什么是方法引用

  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);
}
相关推荐
2401_857610031 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
凌冰_2 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞2 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货2 小时前
Rust 的简介
开发语言·后端·rust
monkey_meng3 小时前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
Estar.Lee3 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书3 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放4 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang4 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net
uzong4 小时前
7 年 Java 后端,面试过程踩过的坑,我就不藏着了
java·后端·面试