【JDK8新特性】方法引用与构造器引用Day3

写在前面

欢迎来到JDK8新特性系列教程的第三天!在Day2中,我们深入学习了函数式接口,了解了Function、Consumer、Supplier、Predicate等核心接口的用法。

今天,我们将学习Lambda表达式的"语法糖"------方法引用(Method Reference) 。如果说Lambda表达式让代码更简洁,那么方法引用则让代码更具可读性。当你看到list.forEach(System.out::println)这样的代码时,是否觉得比list.forEach(s -> System.out.println(s))更加优雅呢?

让我们一起探索方法引用的奥秘吧!

### 目录

  • [写在前面](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [@[TOC](目录)](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [一、什么是方法引用](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [1.1 定义](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [1.2 语法格式](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [1.3 Lambda vs 方法引用对比](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [二、方法引用的四种类型](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [2.1 静态方法引用](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [2.2 实例方法引用(任意对象)](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [2.3 实例方法引用(特定对象)](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [2.4 构造器引用](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [2.5 四种方法引用类型对比表](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [三、方法引用 vs Lambda表达式](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [3.1 什么时候使用方法引用?](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [3.2 对比表格](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [四、构造器引用详解](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [4.1 数组构造器引用](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [4.2 多维数组构造器引用](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [4.3 泛型类的构造器引用](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [五、方法引用的限制条件](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [5.1 方法签名必须匹配](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [5.2 返回类型必须兼容](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [5.3 不能引用可变参数方法(特殊情况)](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [六、踩坑提醒](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [6.1 方法引用不能处理异常](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [6.2 方法引用不能添加额外逻辑](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [6.3 特定对象方法引用的生命周期问题](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [6.4 方法引用与重载的混淆](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [七、面试高频考点](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [7.1 方法引用和Lambda的区别?](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [7.2 方法引用底层是怎么实现的?](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [7.3 四种方法引用类型分别适用于什么场景?](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [7.4 构造器引用如何匹配不同的构造器?](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [八、总结](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [下一步预告](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [参考资料](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)
  • [互动话题](#目录 写在前面 @TOC 一、什么是方法引用 1.1 定义 1.2 语法格式 1.3 Lambda vs 方法引用对比 二、方法引用的四种类型 2.1 静态方法引用 2.2 实例方法引用(任意对象) 2.3 实例方法引用(特定对象) 2.4 构造器引用 2.5 四种方法引用类型对比表 三、方法引用 vs Lambda表达式 3.1 什么时候使用方法引用? 3.2 对比表格 四、构造器引用详解 4.1 数组构造器引用 4.2 多维数组构造器引用 4.3 泛型类的构造器引用 五、方法引用的限制条件 5.1 方法签名必须匹配 5.2 返回类型必须兼容 5.3 不能引用可变参数方法(特殊情况) 六、踩坑提醒 6.1 方法引用不能处理异常 6.2 方法引用不能添加额外逻辑 6.3 特定对象方法引用的生命周期问题 6.4 方法引用与重载的混淆 七、面试高频考点 7.1 方法引用和Lambda的区别? 7.2 方法引用底层是怎么实现的? 7.3 四种方法引用类型分别适用于什么场景? 7.4 构造器引用如何匹配不同的构造器? 八、总结 下一步预告 参考资料 互动话题)

一、什么是方法引用

1.1 定义

**方法引用(Method Reference)**是Lambda表达式的一种简写形式,用于直接引用已经存在的方法。当Lambda表达式只是调用一个已存在的方法时,可以使用方法引用来替代,使代码更加简洁。

1.2 语法格式

方法引用使用双冒号::操作符,基本语法为:

复制代码
类名或对象名::方法名

1.3 Lambda vs 方法引用对比

场景 Lambda表达式 方法引用
静态方法 s -> Integer.parseInt(s) Integer::parseInt
实例方法(任意对象) s -> s.toUpperCase() String::toUpperCase
实例方法(特定对象) () -> obj.getValue() obj::getValue
构造器 () -> new ArrayList<>() ArrayList::new
java 复制代码
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class MethodReferenceIntro {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        
        // Lambda表达式写法
        names.forEach(name -> System.out.println(name));
        
        System.out.println("---");
        
        // 方法引用写法 - 更简洁
        names.forEach(System.out::println);
    }
}

二、方法引用的四种类型

方法引用可以分为以下四种类型:

2.1 静态方法引用

语法类名::静态方法名

适用场景:当Lambda表达式调用的是一个类的静态方法时。

java 复制代码
import java.util.function.Function;
import java.util.function.BiFunction;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StaticMethodReference {
    public static void main(String[] args) {
        // 示例1:字符串转整数
        // Lambda: s -> Integer.parseInt(s)
        Function<String, Integer> parseInt = Integer::parseInt;
        System.out.println(parseInt.apply("123")); // 输出: 123
        
        // 示例2:获取最大值
        // Lambda: (a, b) -> Math.max(a, b)
        BiFunction<Integer, Integer, Integer> max = Math::max;
        System.out.println(max.apply(10, 20)); // 输出: 20
        
        // 示例3:集合处理
        List<String> numbers = Arrays.asList("1", "2", "3", "4", "5");
        List<Integer> ints = numbers.stream()
            .map(Integer::parseInt)  // 静态方法引用
            .collect(Collectors.toList());
        System.out.println(ints); // 输出: [1, 2, 3, 4, 5]
        
        // 示例4:自定义静态方法
        List<String> messages = Arrays.asList("hello", "world", "java");
        messages.stream()
            .map(StringUtils::capitalize)  // 引用自定义静态方法
            .forEach(System.out::println);
        // 输出:
        // Hello
        // World
        // Java
    }
}

class StringUtils {
    public static String capitalize(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
}

2.2 实例方法引用(任意对象)

语法类名::实例方法名

适用场景:当Lambda表达式的第一个参数是实例方法的调用者时。

java 复制代码
import java.util.function.Function;
import java.util.function.BiFunction;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class InstanceMethodReference {
    public static void main(String[] args) {
        // 示例1:字符串转大写
        // Lambda: s -> s.toUpperCase()
        Function<String, String> toUpperCase = String::toUpperCase;
        System.out.println(toUpperCase.apply("hello")); // 输出: HELLO
        
        // 示例2:获取字符串长度
        // Lambda: s -> s.length()
        Function<String, Integer> length = String::length;
        System.out.println(length.apply("Hello")); // 输出: 5
        
        // 示例3:比较字符串
        // Lambda: (s1, s2) -> s1.compareTo(s2)
        BiFunction<String, String, Integer> compare = String::compareTo;
        System.out.println(compare.apply("apple", "banana")); // 输出: 负数
        
        // 示例4:集合处理
        List<String> names = Arrays.asList("  Alice  ", "  Bob  ", "  Charlie  ");
        List<String> trimmed = names.stream()
            .map(String::trim)  // 实例方法引用
            .collect(Collectors.toList());
        System.out.println(trimmed); // 输出: [Alice, Bob, Charlie]
        
        // 示例5:多级方法引用
        List<String> upperNames = names.stream()
            .map(String::trim)
            .map(String::toLowerCase)
            .map(String::toUpperCase)
            .collect(Collectors.toList());
        System.out.println(upperNames); // 输出: [ALICE, BOB, CHARLIE]
    }
}

2.3 实例方法引用(特定对象)

语法对象实例::实例方法名

适用场景:当Lambda表达式调用的是特定对象的实例方法时。

java 复制代码
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.Arrays;
import java.util.List;

public class SpecificObjectMethodReference {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        
        // 示例1:使用特定对象的append方法
        // Lambda: s -> sb.append(s)
        Consumer<String> appendToSb = sb::append;
        appendToSb.accept("Hello");
        appendToSb.accept(" ");
        appendToSb.accept("World");
        System.out.println(sb.toString()); // 输出: Hello World
        
        // 示例2:使用特定对象的方法
        Person person = new Person("Alice", 25);
        Supplier<String> getName = person::getName;
        Supplier<Integer> getAge = person::getAge;
        
        System.out.println(getName.get()); // 输出: Alice
        System.out.println(getAge.get());  // 输出: 25
        
        // 示例3:实际应用场景 - 事件处理
        Button button = new Button("Click Me");
        EventHandler handler = new EventHandler();
        
        // 注册特定对象的方法作为回调
        button.setOnClick(handler::onClick);
        button.click(); // 输出: Button clicked!
        
        // 示例4:集合遍历
        List<String> messages = Arrays.asList("Line 1", "Line 2", "Line 3");
        Printer printer = new Printer("[LOG] ");
        messages.forEach(printer::print);
        // 输出:
        // [LOG] Line 1
        // [LOG] Line 2
        // [LOG] Line 3
    }
}

class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() { return name; }
    public int getAge() { return age; }
}

class Button {
    private String label;
    private Runnable onClick;
    
    public Button(String label) {
        this.label = label;
    }
    
    public void setOnClick(Runnable onClick) {
        this.onClick = onClick;
    }
    
    public void click() {
        if (onClick != null) {
            onClick.run();
        }
    }
}

class EventHandler {
    public void onClick() {
        System.out.println("Button clicked!");
    }
}

class Printer {
    private String prefix;
    
    public Printer(String prefix) {
        this.prefix = prefix;
    }
    
    public void print(String message) {
        System.out.println(prefix + message);
    }
}

2.4 构造器引用

语法类名::new

适用场景:当Lambda表达式创建新对象时。

java 复制代码
import java.util.function.Supplier;
import java.util.function.Function;
import java.util.function.BiFunction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ConstructorReference {
    public static void main(String[] args) {
        // 示例1:无参构造器
        // Lambda: () -> new ArrayList<>()
        Supplier<List<String>> listSupplier = ArrayList::new;
        List<String> list = listSupplier.get();
        list.add("Hello");
        System.out.println(list); // 输出: [Hello]
        
        // 示例2:单参数构造器
        // Lambda: capacity -> new ArrayList<>(capacity)
        Function<Integer, List<String>> sizedListSupplier = ArrayList::new;
        List<String> sizedList = sizedListSupplier.apply(100);
        System.out.println(sizedList.size()); // 输出: 0(初始容量为100,但size为0)
        
        // 示例3:双参数构造器
        // Lambda: (k, v) -> new HashMap<>(k, v)  // 这里用Person示例
        BiFunction<String, Integer, Person> personCreator = Person::new;
        Person person = personCreator.apply("Alice", 25);
        System.out.println(person); // 输出: Person{name='Alice', age=25}
        
        // 示例4:Map的computeIfAbsent使用构造器引用
        Map<String, List<String>> map = new HashMap<>();
        // 如果key不存在,创建一个新的ArrayList
        List<String> values = map.computeIfAbsent("key", k -> new ArrayList<>());
        // 或者使用方法引用
        List<String> values2 = map.computeIfAbsent("key2", ArrayList::new);
        
        // 示例5:流操作中使用构造器引用
        List<String> names = java.util.Arrays.asList("Alice", "Bob", "Charlie");
        List<Person> people = names.stream()
            .map(name -> new Person(name, 0))  // Lambda
            .collect(java.util.stream.Collectors.toList());
        
        // 如果有合适的构造器,可以使用构造器引用
        // 这里假设Person有一个只接受name的构造器
        // List<Person> people2 = names.stream()
        //     .map(Person::new)
        //     .collect(Collectors.toList());
    }
}

class Person {
    private String name;
    private int age;
    
    public Person() {
        this.name = "Unknown";
        this.age = 0;
    }
    
    public Person(String name) {
        this.name = name;
        this.age = 0;
    }
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

2.5 四种方法引用类型对比表

类型 语法 Lambda等价形式 示例
静态方法引用 类名::静态方法 (args) -> 类名.静态方法(args) Integer::parseInt
实例方法引用(任意对象) 类名::实例方法 (obj, args) -> obj.实例方法(args) String::length
实例方法引用(特定对象) 对象::实例方法 (args) -> 对象.实例方法(args) sb::append
构造器引用 类名::new (args) -> new 类名(args) ArrayList::new

三、方法引用 vs Lambda表达式

3.1 什么时候使用方法引用?

使用方法引用的情况

  1. 代码更简洁:当Lambda表达式只是简单地调用一个已存在的方法时
  2. 提高可读性:方法名本身就能说明操作意图时
  3. 避免重复:需要多次使用相同的方法逻辑时
java 复制代码
import java.util.Arrays;
import java.util.List;

public class WhenToUseMethodReference {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        
        // 推荐:使用方法引用 - 简洁清晰
        names.stream()
            .map(String::toUpperCase)
            .forEach(System.out::println);
        
        // 不推荐:使用Lambda - 冗余
        names.stream()
            .map(s -> s.toUpperCase())
            .forEach(s -> System.out.println(s));
    }
}

使用Lambda表达式的情况

  1. 需要额外逻辑:方法引用无法满足需求时
  2. 参数需要转换:需要对参数进行处理后再调用方法时
  3. 需要多步操作:一个表达式无法完成时
java 复制代码
import java.util.Arrays;
import java.util.List;

public class WhenToUseLambda {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        
        // 必须使用Lambda:需要额外逻辑
        names.stream()
            .map(s -> s + " - " + s.length())  // 无法使用方法引用
            .forEach(System.out::println);
        
        // 必须使用Lambda:参数需要转换
        names.stream()
            .map(s -> s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase())
            .forEach(System.out::println);
        
        // 必须使用Lambda:多步操作
        names.stream()
            .map(s -> {
                String upper = s.toUpperCase();
                return "[" + upper + "]";
            })
            .forEach(System.out::println);
    }
}

3.2 对比表格

场景 推荐写法 原因
简单方法调用 方法引用 更简洁、可读性更好
需要参数处理 Lambda 方法引用无法实现
需要多步操作 Lambda 方法引用只能单步
需要条件判断 Lambda 方法引用无法包含逻辑
需要异常处理 Lambda 方法引用无法try-catch

四、构造器引用详解

4.1 数组构造器引用

数组也可以使用方法引用创建:

java 复制代码
import java.util.function.IntFunction;
import java.util.Arrays;

public class ArrayConstructorReference {
    public static void main(String[] args) {
        // 创建String数组
        IntFunction<String[]> arrayCreator = String[]::new;
        String[] array = arrayCreator.apply(5);
        System.out.println(array.length); // 输出: 5
        
        // 在Stream中使用
        java.util.List<String> names = java.util.Arrays.asList("Alice", "Bob", "Charlie");
        String[] nameArray = names.stream()
            .toArray(String[]::new);
        System.out.println(Arrays.toString(nameArray)); // 输出: [Alice, Bob, Charlie]
        
        // 对比:不使用方法引用
        String[] nameArray2 = names.stream()
            .toArray(size -> new String[size]);
        
        // 创建int数组(注意:基本类型数组需要特殊处理)
        IntFunction<int[]> intArrayCreator = int[]::new;
        int[] intArray = intArrayCreator.apply(10);
        System.out.println(intArray.length); // 输出: 10
    }
}

4.2 多维数组构造器引用

java 复制代码
import java.util.function.Function;
import java.util.function.BiFunction;

public class MultiDimensionalArrayReference {
    public static void main(String[] args) {
        // 二维数组
        Function<Integer, int[][]> matrixCreator = int[][]::new;
        int[][] matrix = matrixCreator.apply(3);
        System.out.println(matrix.length); // 输出: 3
        
        // 注意:多维数组的完整创建仍需手动初始化
        for (int i = 0; i < matrix.length; i++) {
            matrix[i] = new int[4];
        }
        System.out.println(matrix[0].length); // 输出: 4
    }
}

4.3 泛型类的构造器引用

java 复制代码
import java.util.function.Supplier;
import java.util.function.Function;

public class GenericConstructorReference {
    public static void main(String[] args) {
        // 创建泛型容器
        Supplier<Container<String>> stringContainer = Container<String>::new;
        Container<String> sc = stringContainer.get();
        sc.setItem("Hello");
        System.out.println(sc.getItem()); // 输出: Hello
        
        // 带初始值的构造器引用
        Function<String, Container<String>> initializedContainer = Container<String>::new;
        Container<String> ic = initializedContainer.apply("World");
        System.out.println(ic.getItem()); // 输出: World
    }
}

class Container<T> {
    private T item;
    
    public Container() {
        this.item = null;
    }
    
    public Container(T item) {
        this.item = item;
    }
    
    public void setItem(T item) {
        this.item = item;
    }
    
    public T getItem() {
        return item;
    }
}

五、方法引用的限制条件

5.1 方法签名必须匹配

方法引用要求被引用的方法签名必须与函数式接口的抽象方法兼容:

java 复制代码
import java.util.function.Function;
import java.util.function.BiFunction;

public class MethodReferenceLimitations {
    public static void main(String[] args) {
        // 正确:签名匹配
        Function<String, Integer> parseInt = Integer::parseInt;
        // Integer.parseInt(String s) 匹配 Function<String, Integer>
        
        // 错误:签名不匹配
        // Function<String, Integer> valueOf = Integer::valueOf;
        // 实际上这是可以的,因为valueOf(String)返回Integer
        
        // 错误示例:参数数量不匹配
        // Function<String, Integer> max = Math::max;
        // 编译错误:Math.max需要两个参数,但Function只需要一个
        
        // 正确:使用BiFunction
        BiFunction<Integer, Integer, Integer> max = Math::max;
        System.out.println(max.apply(10, 20)); // 输出: 20
    }
}

5.2 返回类型必须兼容

java 复制代码
import java.util.function.Function;

public class ReturnTypeCompatibility {
    public static void main(String[] args) {
        // 正确:返回类型完全匹配
        Function<String, Integer> length = String::length;
        
        // 正确:返回类型是目标类型的子类
        Function<String, Number> lengthAsNumber = String::length;
        // Integer是Number的子类
        
        // 错误:返回类型不兼容
        // Function<String, String> lengthAsString = String::length;
        // 编译错误:Integer不能赋值给String
    }
}

5.3 不能引用可变参数方法(特殊情况)

java 复制代码
import java.util.function.BiFunction;
import java.util.function.Function;

public class VarargsLimitation {
    public static void main(String[] args) {
        // Arrays.asList是可变参数方法
        // 可以直接引用
        Function<String[], java.util.List<String>> asList = Arrays::asList;
        
        // 但是以下情况会有限制
        // 当函数式接口的参数数量与可变参数不匹配时
        
        // 正确:数组作为参数
        String[] arr = {"a", "b", "c"};
        java.util.List<String> list = asList.apply(arr);
        System.out.println(list); // 输出: [a, b, c]
    }
}

六、踩坑提醒

6.1 方法引用不能处理异常

坑点:方法引用无法处理受检异常,如果被引用的方法抛出受检异常,编译会失败。

java 复制代码
import java.io.IOException;
import java.util.function.Function;

public class ExceptionHandlingPitfall {
    public static void main(String[] args) {
        // 错误:无法使用方法引用处理受检异常
        // Function<String, String> readFile = ExceptionHandlingPitfall::readFile;
        // 编译错误:readFile抛出IOException,但Function.apply不声明异常
        
        // 正确做法:使用Lambda并处理异常
        Function<String, String> readFileSafe = path -> {
            try {
                return readFile(path);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        };
        
        // 或者包装成运行时异常
        Function<String, String> readFileWrapped = path -> {
            try {
                return readFile(path);
            } catch (IOException e) {
                return "Error: " + e.getMessage();
            }
        };
    }
    
    public static String readFile(String path) throws IOException {
        // 模拟读取文件
        if (path == null) {
            throw new IOException("Path is null");
        }
        return "Content of " + path;
    }
}

6.2 方法引用不能添加额外逻辑

坑点:方法引用只是简单的方法调用,无法添加额外的处理逻辑。

java 复制代码
import java.util.function.Consumer;

public class NoExtraLogicPitfall {
    public static void main(String[] args) {
        // 需求:打印前添加前缀
        
        // 错误:方法引用无法实现
        // Consumer<String> printWithPrefix = System.out::println;
        // 无法添加前缀逻辑
        
        // 正确:使用Lambda
        Consumer<String> printWithPrefix = s -> System.out.println("[LOG] " + s);
        printWithPrefix.accept("Hello"); // 输出: [LOG] Hello
        
        // 需求:打印非空字符串
        Consumer<String> printIfNotEmpty = s -> {
            if (s != null && !s.isEmpty()) {
                System.out.println(s);
            }
        };
        printIfNotEmpty.accept("Hello"); // 输出: Hello
        printIfNotEmpty.accept("");      // 无输出
    }
}

6.3 特定对象方法引用的生命周期问题

坑点:使用特定对象的方法引用时,要注意对象的生命周期,避免内存泄漏或空指针。

java 复制代码
import java.util.function.Consumer;
import java.util.ArrayList;
import java.util.List;

public class LifecyclePitfall {
    public static void main(String[] args) {
        // 危险:引用可能为null的对象
        StringBuilder sb = null;
        // Consumer<String> append = sb::append;  // 编译错误,sb为null
        
        // 危险:对象可能被修改或置空
        StringBuilder mutableSb = new StringBuilder();
        Consumer<String> appender = mutableSb::append;
        
        appender.accept("Hello");
        System.out.println(mutableSb.toString()); // 输出: Hello
        
        // 如果此时mutableSb被其他代码修改或置空
        // appender仍然持有对原对象的引用,可能导致意外行为
        
        // 建议:确保对象在方法引用使用期间有效
        final StringBuilder safeSb = new StringBuilder();
        Consumer<String> safeAppender = safeSb::append;
        safeAppender.accept("World");
        System.out.println(safeSb.toString()); // 输出: World
    }
}

6.4 方法引用与重载的混淆

坑点:当存在多个重载方法时,编译器可能无法确定使用哪个方法。

java 复制代码
import java.util.function.Function;
import java.util.function.BiFunction;

public class OverloadingConfusion {
    public static void main(String[] args) {
        // Integer.valueOf有多个重载版本
        // valueOf(int i) 和 valueOf(String s)
        
        // 正确:根据函数式接口推断
        Function<String, Integer> fromString = Integer::valueOf;  // 使用valueOf(String)
        Function<Integer, Integer> fromInt = Integer::valueOf;    // 使用valueOf(int)
        
        System.out.println(fromString.apply("123")); // 输出: 123
        System.out.println(fromInt.apply(456));      // 输出: 456
        
        // 错误:无法推断时使用哪个重载
        // 以下代码在某些复杂情况下可能需要显式类型转换
    }
}

七、面试高频考点

7.1 方法引用和Lambda的区别?

特性 方法引用 Lambda表达式
语法复杂度 更简洁 相对冗长
表达能力 只能简单调用 可以包含复杂逻辑
可读性 方法名即说明意图 需要阅读代码理解
异常处理 无法处理受检异常 可以try-catch
额外逻辑 无法添加 可以添加任意逻辑
底层实现 编译器生成静态方法 生成 invokedynamic

核心区别:方法引用是Lambda的语法糖,用于简化"直接调用已有方法"的场景。当需要额外逻辑时,必须使用Lambda。

7.2 方法引用底层是怎么实现的?

实现原理

  1. 编译期 :编译器将方法引用转换为字节码中的invokedynamic指令
  2. 运行时:JVM使用LambdaMetafactory生成实现函数式接口的类
  3. 方法句柄:内部使用MethodHandle来调用被引用的方法
java 复制代码
// 源码
list.forEach(System.out::println);

// 大致等价的底层实现(概念性展示)
// 编译器生成类似以下的字节码:
// invokedynamic accept:()Ljava/util/function/Consumer; [
//     LambdaMetafactory.metafactory(...)
//     MethodHandle.println(Object)void
// ]

性能特点

  • 第一次调用时有初始化开销(生成调用站点)
  • 后续调用性能与直接方法调用相当
  • 比匿名内部类方式更高效(无额外的类加载)

7.3 四种方法引用类型分别适用于什么场景?

类型 适用场景 示例
静态方法引用 工具类方法、通用算法 Integer::parseIntMath::max
实例方法引用(任意对象) 对集合元素进行统一操作 String::toUpperCaseObject::toString
实例方法引用(特定对象) 回调函数、事件处理、状态操作 sb::appendprinter::print
构造器引用 工厂模式、对象创建 ArrayList::newPerson::new

7.4 构造器引用如何匹配不同的构造器?

编译器根据函数式接口的方法签名来匹配对应的构造器:

java 复制代码
// Function<Integer, ArrayList<String>> 匹配 ArrayList(int initialCapacity)
// Supplier<ArrayList<String>> 匹配 ArrayList()
// BiFunction<String, Integer, Person> 匹配 Person(String, int)

匹配规则:

  1. 参数类型和数量必须匹配
  2. 返回类型必须是创建的类或其子类
  3. 如果存在多个匹配的构造器,编译器选择最具体的那个

八、总结

今天我们深入学习了JDK8的方法引用与构造器引用,主要内容包括:

  1. 方法引用的概念 :Lambda表达式的语法糖,使用::操作符
  2. 四种类型
    • 静态方法引用:类名::静态方法
    • 实例方法引用(任意对象):类名::实例方法
    • 实例方法引用(特定对象):对象::实例方法
    • 构造器引用:类名::new
  3. 方法引用 vs Lambda:方法引用更简洁,但Lambda更灵活
  4. 构造器引用详解:包括数组构造器引用
  5. 限制条件:签名匹配、返回类型兼容
  6. 常见坑点:异常处理、额外逻辑、生命周期问题

下一步预告

在Day4中,我们将进入JDK8最强大的特性之一------Stream API(上)。我们将学习:

  • Stream的创建方式
  • Stream的中间操作(filter、map、sorted等)
  • Stream的终止操作(collect、reduce等)
  • Stream的惰性求值特性

Stream API将彻底改变你处理集合数据的方式,敬请期待!


参考资料

  1. Java 8 Method References官方文档
  2. Java 8 Method Reference详解
  3. 深入理解Java 8 Lambda和方法引用

互动话题

  1. 你在项目中更喜欢用方法引用还是Lambda?为什么?
  2. 有没有遇到过方法引用无法满足需求的情况?是如何解决的?
  3. 你觉得方法引用让Java代码变得更易读还是更难理解了?

欢迎在评论区分享你的观点和经验,我们Day4见!

相关推荐
在繁华处12 小时前
从零搭建轻灵(五):记忆系统与生产化特性
java·jvm·oracle
子榆.12 小时前
CANN自定义GEMM算子(Ascend C手写高性能矩阵乘法)
c语言·开发语言·矩阵
天若有情67312 小时前
Deepseek-V4-Flash-20260423 深度评测与实战指南
java·大数据·网络·ai
折哥的程序人生 · 物流技术专研12 小时前
《Java 100 天进阶之路》第32篇:Java常用工具类(Objects、Collections、Arrays深入)
java·后端·面试·求职招聘
憧憬成为java架构高手的小白12 小时前
苍穹外卖项目-day02
java·spring
LB211212 小时前
C++通讯录课设(西安石油大学)
开发语言·c++·算法
西凉的悲伤13 小时前
SpringBoot RestTemplate 介绍
java·spring boot·后端·resttemplate
专注VB编程开发20年14 小时前
python语法设计、IDE 生态、平台策略、解析器逻辑这四层的矛盾点
开发语言·ide·python
Roselind_Yi14 小时前
池化对比:CNN池化 VS Java线程池
java·人工智能·经验分享·笔记·深度学习·神经网络·cnn