方法引用需通过实践掌握,核心四步:认全类型、盯准签名、动手改代码、卡住边界;从静态、实例、类名调用三类高频场景入手,死磕签名匹配,专练构造器与数组引用,并避开日志、默认值、组合操作等硬套陷阱。

直接上手练,别等“全学会”再动——方法引用不是背出来的,是写出来、错出来、调出来、用熟的。核心就四步:先认全类型、再盯准签名、动手改代码、最后卡住边界。
一、从最常用的三种开始,边写边记
不用一次啃完五种,先拿下高频场景:
-
静态方法引用:比如
Integer::parseInt替代s -> Integer.parseInt(s)。找一段字符串转数字的流操作,把 Lambda 全替成 :: 写法,跑通再改参数类型试试是否报错 -
对象实例方法引用:比如
System.out::println或自定义对象如printer::print。重点体会“对象已存在”这个前提——不能写new Printer()::print(会重复创建) -
类名调实例方法:比如
String::length或String::compareToIgnoreCase。它本质是把流中每个元素当主调对象,所以list.stream().map(String::toUpperCase)等价于s -> s.toUpperCase()
二、死磕“签名匹配”,这是卡壳主因
方法引用能用,不是看名字像,而是函数式接口抽象方法和被引用方法的参数个数、顺序、类型、返回值必须对得上。练法很实在:
- 拿
Function<String, Integer>接口练:能用String::length(1入1出),但不能用String::startsWith(需要额外 String 参数) - 拿
Consumer<String>练:能用System.out::println,但不能用Integer::parseInt(返回 int,不是 void) - 故意写错一个,比如
list.sort(String::length),观察编译错误提示——它会明确告诉你“找不到接受两个 String 的 length 方法”,这就是签名不匹配的铁证
三、构造器和数组引用,专练“new”的替代
这两类容易忽略,但面试常问:
立即学习“Java免费学习笔记(深入)”;
-
构造器引用:写
Supplier<ArrayList<String>> sup = ArrayList::new,然后sup.get();再试带参构造,比如BiFunction<String, Double, Car> creator = Car::new,确认参数数量和类型是否和构造器一致 -
数组引用:
IntFunction<int[]> arrCreator = int[]::new,接着int[] a = arrCreator.apply(5)——生成长度为 5 的空数组。注意语法是类型[]::new,不是int::new
四、实战防坑:哪些地方不能硬套
方法引用不是万能缩写,强行用反而翻车。练的时候主动设陷阱:
- 想加日志?
s -> { System.out.println(s); return s.toUpperCase(); }→ 不能用String::toUpperCase,因为多了副作用 - 要默认值?
s -> s == null ? "N/A" : s.trim()→ 不能直接引用String::trim,null 会 NPE - 要组合操作?
s -> "ID_" + s.toUpperCase()→ 不能用方法引用一步到位,要么拆成两步流,要么封装成独立方法再引
不复杂但容易忽略:练的本质不是记住语法,而是建立“看到 Lambda 就下意识想能不能换 ::”的肌肉记忆。每天改 3 段旧代码,坚持一周,开口讲原理时自然有底气。


















