方法引用需先写通lambda再简化,必须匹配函数式接口的参数与返回值类型,分五种形式刻意练习,并通过三步排查编译错误。

方法引用不是靠背出来的,是靠写对、写顺、写熟练出来的。核心就一条:先写通 Lambda,再看能不能缩成方法引用;缩不成功,说明参数或语义没对齐。
从 Lambda 出发,自然过渡
别一上来就记“类名::方法名”这种格式。每次用方法引用前,先写出等价的 Lambda 表达式,再对照着删掉冗余部分:
- 写
s -> System.out.println(s)→ 发现只是把参数原样传给println→ 替换成System.out::println - 写
s -> s.length()→ 发现是让每个字符串自己调自己的length()→ 替换成String::length - 写
(s1, s2) -> s1.compareToIgnoreCase(s2)→ 发现是让第一个字符串调用方法,第二个当参数 → 替换成String::compareToIgnoreCase
盯住函数式接口,反推引用是否合法
方法引用能用的前提,是它所处的位置必须是一个函数式接口(比如 Function、Consumer、Comparator)。光有 :: 不行,得看上下文要什么:
-
map(Integer::parseInt)成立,因为Function<string integer></string>要一个入参、一个出参,而Integer.parseInt(String)刚好匹配 -
filter(String::isEmpty)成立,因为Predicate<string></string>要一个入参、返回 boolean,String.isEmpty()也满足 - 但
list.forEach(String::length)会报错——forEach需要Consumer<string></string>(接受 String,无返回),而length()返回 int,类型不匹配
分场景刻意练习五种形式
每种类型用 2–3 行真实代码练一次,比看十遍总结管用:
-
静态方法引用:用
Arrays.asList("1", "2", "3").stream().map(Double::parseDouble) -
对象实例引用:用
PrintStream out = System.err; list.forEach(out::println) -
类任意对象引用:用
list.stream().sorted(String::compareTo).collect(toList()) -
构造器引用:用
Stream.of("a", "b").map(Student::new).collect(toList())(前提是Student(String)存在) -
数组构造引用:用
Function<integer string> fun = String[]::new; String[] arr = fun.apply(5);</integer>
遇到报错,先查三件事
编译失败时,别急着搜错误信息,直接问自己:
- 目标位置是不是函数式接口?比如写在
if里或普通方法调用处,肯定不行 - 被引用的方法是否存在?拼写对不对?是不是 private 或包私有?
- 参数个数、类型、顺序,和返回值,跟函数式接口的抽象方法是否完全一致?注意
String::toLowerCase是无参方法,只能用于Function<string string></string>类型,不能用于Consumer<string></string>
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











