avatar

一条在知识海洋的咸鱼

这个家伙很懒,啥也没有留下😋

  • 首页
  • Linux
  • OCJP
  • Java核心技术卷
  • J2EE相关标准
  • 深入理解Java虚拟机
  • NIO与SOcket编程技术指南
  • Java多线程编程核心技术
  • Redis开发与运维
  • Spring Cloud Alibaba 微服务原理与实践
  • DevOps
  • Docker
  • MySQL必知必会
  • AI自学路线
  • Spring Boot 编程思想(核心篇)
主页 第十一章 方法引用
文章

第十一章 方法引用

发表于 2021-05-13 更新于 2026-06- 10
作者 Administrator
31~40 分钟 阅读

对 Streams 使用方法引用

  • 使用像对象一样使用方法
    • 方法引用
      • 方法引用类型
  • 静态方法
  • 特定类型对象的实例方法
    • 方法没有入参示例
    • 方法有入参实例
  • 现有对象的实例方法
  • 构造函数
    • 无参构造,使用Supplier
    • 构造函数含有1个入参,使用Function
    • 构造函数含有2个入参,使用Function
    • 三个及以上入参,使用自定义接口
  • 总结

使用像对象一样使用方法

  • 使用对象
    我们可以使用对象的引用,或者通过创建新的对象
List list = new ArrayList();
store(new ArrayList());
  • 使用方法
    我们只在另一个方法中使用对象的方法,仍然必须将完整对象作为参数传递。将方法作为参数传递不是更实用吗
    使用lambda 表达式,可以做类似的事情。我们可以使用方法,因为方法引用是只执行 lambda 表达式的一个简写语法。

方法引用

Object :: methodName
  • 使用 lambda 表达式,而不是使用匿名类。但有时,lambda 表达式实际上只是对某个方法的调用
Consumer<String> c = s -> System.out.println(s);

为了使代码更清晰,可以将 lambda 表达式转换为方法引用

Consumer<String> c = System.out::println;
  • 格式
    包含该方法的对象(或类)放在:: 操作符之前,并将方法名放在没有参数的方法之后
  • 限制
    方法引用不能用于任何方法。它们只能用于替换单方法 lambda 表达式。
    要使用方法引用,首先需要一个带有一个方法的 lambda 表达式。要使用 lambda 表达式,首先需要一个函数接口,一个只有一个抽象方法的接口。

方法引用类型

1.引用静态static方法
2.引用特定类型的对象实例方法
3.引用已有对象的实例方法
4.引用构造器方法

静态方法

  • lambda形式
(args) -> Class.staticMethod(args)
  • 方法引用形式
Class::staticMethod

1.使用: : 运算符,并且不向方法引用传递参数
2.不必将参数传递给方法引用。但是,参数的处理取决于方法引用的类型
3.只要可以传递一个只调用静态方法的 lambda 表达式,我们就可以使用方法引用

class Numbers {
    public static boolean isMoreThanFifty(int n1, int n2) {
        return (n1 + n2) > 50;
    }
    public static List<Integer> findNumbers(
            List<Integer> l, BiPredicate<Integer, Integer> p) {
        List<Integer> newList = new ArrayList<>();
        for(Integer i : l) {
            if(p.test(i, i + 10)) {
                newList.add(i);
            }
        }
        return newList;
    }
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(12,5,45,18,33,24,40);
// Using an anonymous class
        List<Integer> numbers = findNumbers(list, new BiPredicate<Integer, Integer>() {
            @Override
            public boolean test(Integer i1, Integer i2) {
                return Numbers.isMoreThanFifty(i1, i2);
            }
        });
// Using a lambda expression
        List<Integer> numbers1 = findNumbers(list, (i1, i2) -> Numbers.isMoreThanFifty(i1, i2));
// Using a method reference
        List<Integer> numbers2 = findNumbers(list, Numbers::isMoreThanFifty);
        System.out.println(numbers+""+numbers1+""+numbers2);
    }
}

上述代码分别使用匿名内部类,lambda表达式和方法引用其输出都是一样的
image.png

特定类型对象的实例方法

传递一个对象的实例,其中一个方法使用一些可选参数执行

  • lambda形式
(obj, args) -> obj.instanceMethod(args)
ObjectType::instanceMethod

1.在方法引用中,我们不使用实例本身。我们使用它的类型。
2.lambda 表达式的另一个参数(如果有的话)并没有在方法引用中使用,但是它像静态方法一样被传递到幕后

方法没有入参示例

class Shipment {
    static Double i = 0.0d;
    public double calculateWeight() {
        double weight = i++;
        // Calculate weight
        return weight;
    }
}
class C {
    public static List<Double> calculateOnShipments(
            List<Shipment> l, Function<Shipment, Double> f) {
        List<Double> results = new ArrayList<>();
        for (Shipment s : l) {
            results.add(f.apply(s));
        }
        return results;
    }
    public static void main(String[] args) {
        List<Shipment> l = new ArrayList<Shipment>();
        l.add(new Shipment());
        l.add(new Shipment());
// Using an anonymous class
        List<Double> doubles = calculateOnShipments(l, new Function<Shipment, Double>() {
            @Override
            public Double apply(Shipment s) { // The object
                return s.calculateWeight(); // The method
            }
        });
// Using a lambda expression
        List<Double> doubles1 = calculateOnShipments(l, s -> s.calculateWeight());
// Using a method reference
        List<Double> doubles2 = calculateOnShipments(l, Shipment::calculateWeight);
        System.out.println(doubles);
        System.out.println(doubles1);
        System.out.println(doubles2);
    }
}

其结果不同,但计算逻辑是相同的。不管是匿名内部类还是lambda或方法引用,都是先使用calculateOnShipments方法遍历shipment集合里面的元素,后使用重写后的Function接口使得static先赋值后再自增1,返回Double元素
image.png

方法有入参实例

JDK自带的Function类型函数式接口含有2个入参或1个入参类型,没有3个入参类型,自定义一个3个入参函数式接口

interface TriFunction<T, U, V, R> {
    R apply(T t, U u, V v);
}

可以使用匿名类或者lambda表达式或者方法引用,甚至隐藏其实现,封装在另一个方法中

class Sum {
    Integer doSum(String s1, String s2) {
        return Integer.parseInt(s1) + Integer.parseInt(s2);
    }

    public static void main(String[] args) {
        TriFunction<Sum, String, String, Integer> anon =
                new TriFunction<Sum, String, String, Integer>() {
                    @Override
                    public Integer apply(Sum s, String arg1, String arg2) {
                        return s.doSum(arg1, arg2);
                    }
                };
        System.out.println(anon.apply(new Sum(), "1", "4"));

        TriFunction<Sum, String, String, Integer> lambda =
                (Sum s, String arg1, String arg2) -> s.doSum(arg1, arg2);
        System.out.println(lambda.apply(new Sum(), "1", "4"));
        TriFunction<Sum, String, String, Integer> mRef = Sum::doSum;
        System.out.println(mRef.apply(new Sum(), "1", "4"));
        System.out.println(integer(new Sum(), "1", "4"));
    }

    static Integer integer(Sum sum, String s, String i) {
        TriFunction<Sum, String, String, Integer> anon =
                new TriFunction<Sum, String, String, Integer>() {
                    @Override
                    public Integer apply(Sum s, String arg1, String arg2) {
                        return s.doSum(arg1, arg2);
                    }
                };
        return anon.apply(sum, "1", "4");
    }
}

image.png

  • 参数解释
    TriFunction < Sum,String,String,Integer >
    1.TriFunction第一个类型参数包含要执行的方法的对象类型,当然内部也可以new一个固定的,但是不通用了,函数式接口应该面向任何类或者对象
    2.第二个类型参数是方法入参的第一个参数的类型
    3.第三个类型参数是方法入参的第二个参数的类型
    4.第四个参数类型是要执行的方法的返回类型。
  • lambda版本
(Sum s, String arg1, String arg2) -> s.doSum(arg1, arg2)
  • 方法引用
Sum::doSum

看起来很怪,但非常简洁🤣

现有对象的实例方法

  • lambda形式
(args) -> obj.instanceMethod(args)
obj::instanceMethod
class Car {
     private int id;
     private String color;
     // More properties
     // And getter and setters
}
class Mechanic {
     public void fix(Car c) {
         System.out.println("Fixing car " + c.getId());
     }
}

image.png

构造函数

  • lambda形式
(args) -> new ClassName(args)
ClassName::new

lambda 表达式唯一要做的就是创建一个新对象,因此我们只需用关键字 new 引用类的一个构造函数。与其他情况一样,参数(如果有的话)没有传递到方法引用中
一般与 java.util.function包的两个(或三个)接口使用此语法

无参构造,使用Supplier

// Using an anonymous class
Supplier<List<String>> s = new Supplier() {
     public List<String> get() {
         return new ArrayList<String>();
     }
};
List<String> l = s.get();

// Using a lambda expression
Supplier<List<String>> s = () -> new ArrayList<String>();
List<String> l = s.get();

// Using a method reference
Supplier<List<String>> s = ArrayList::new;
List<String> l = s.get();

image.png

构造函数含有1个入参,使用Function

// Using a anonymous class
Function<String, Integer> f =
     new Function<String, Integer>() {
         public Integer apply(String s) {
             return new Integer(s);
         }
};
Integer i = f.apply("100");

// Using a lambda expression
Function<String, Integer> f = s -> new Integer(s);
Integer i = f.apply("100");

// Using a method reference
Function<String, Integer> f = Integer::new;
Integer i = f.apply("100");

image.png

构造函数含有2个入参,使用Function

// Using a anonymous class
BiFunction<String, String, Locale> f = new BiFunction<String, String, Locale>() {
     public Locale apply(String lang, String country) {
         return new Locale(lang, country);
     }
};
Locale loc = f.apply("en","UK");

// Using a lambda expression
BiFunction<String, String, Locale> f = (lang, country) -> new Locale(lang, country);
Locale loc = f.apply("en","UK");

// Using a method reference
BiFunction<String, String, Locale> f = Locale::new;
Locale loc = f.apply("en","UK");

image.png

三个及以上入参,使用自定义接口

可以自定义Function类型的函数式接口实现

引用构造函数与引用静态方法非常相似。区别在于构造函数“方法名”是new

总结

1.方法引用是只执行一个方法的lambda表达式的简写语法。
2.如果方法引用能够使代码更加清晰,那么就使用它
3.方法引用有四种类型:
对静态方法的方法引用
对特定类型对象的实例方法的方法引用
对现有对象的实例方法的方法引用
对构造函数的方法引用

OCJP
许可协议: 
分享

相关文章

9月 6, 2021

关于这篇OCP-Java专题说明

5月 28, 2021

三十章 本地化

通过使用 Locale 对象读取和设置 Locale。创建并读取属性文件。为每个区域设置构建资源包,并在应用程序中加载资源包。本地化设置语言环境本地化设计一个能够处理不同语言和地区的应用程序。最常见的是消息、日期和数字。java.util.LocaleLocale类基本上代表一种语言和一个国家获得机

5月 27, 2021

第二十九章 JDBC API

了解JDBC API 核心的接口,包括 Driver、 Connection、 Statement 和 ResultSet 接口及其与提供者实现的关系。使用 DriverManager 类(包括 JDBC URL)标识连接到数据库所需的组件。从数据库提交查询和读取结果,包括创建语句、返回结果集、遍历

下一篇

第十二章 Stream流

上一篇

第十章 Java内置Lambda接口

最近更新

  • 55 异常兜底:工具失败、非法输出、空检索与超时
  • 54 Agent Memory:短期记忆、用户上下文与摘要
  • 53 Human-in-the-loop:让关键动作暂停、确认与恢复
  • 52 工单 Tool:字段校验、创建结果与失败补偿
  • 51 订单 Tool:Mock、鉴权、状态解析与脱敏

热门标签

java基础 微服务 maven Spring Tomcat DDD Linux Linux基础 SQL基础 数据结构算法

目录

©2026 一条在知识海洋的咸鱼. 保留部分权利。

使用 Halo 主题 Chirpy