当前位置: 首页 > news >正文

秒懂Java之方法引用(method reference)详解

概述

如果你对将Lambda表达式转换成对应的方法引用有疑惑的话,本文你值得一看。

方法引用(MethodReference)是Lambda表达式的另一种格式,在某些场景下可以提高代码的可读性,那么如何将一个Lambda表达式替换成MethodReference呢?

使用条件

只可以替换单方法的Lambda表达式

什么意思呢 ?

例如下面这个Lambda表达式就不可以使用方法引用替换,因为其不是单方法的,有好几行呢。如果想要使用方法引用就需要将lambda结构体重构为一个方法。

Predicate<Integer> p2 = integer -> {System.out.println("你好 世界!");return TestUtil.isBiggerThan3(integer);};

下面这个就可以使用方法引用替换了

Predicate<Integer> p2 = integer -> TestUtil.isBiggerThan3(integer);

使用场景

当使用方法引用替换Lambda表达式具有更好的可读性时,考虑使用。

如何使用
曾几何时,我对方法引用的理解很模糊,一般是使用IDE协助转换,但是转换后的写法很多我都不明白:

Lambda的参数哪去了?
为什么::前面有的是类名称,有的是实例对象呢?
不是只有静态方法::前面才使用类名吗,怎么有的实例方法也使用类名啊?
为什么 ClassName::new 有时要求无参构造器,有时又要求有参构造器呢?构造器参数由什么决定呢?
结论其实显而易见了,我对方法引用的理解根本就是一团浆糊!如果你也有上面的疑问,也许应该接着往下看。

方法引用的类型

解决纷繁复杂信息的最好方式就是分类,这里也不例外。方法引用可以分为分四类,只要掌握了类型区别一切就变得易如反掌了。为行文方便,这里先列出要使用的类:

TestUtil里面有一个静态方法,一个实例方法。Student是一个普通实体类 ,具体如下代码所示

public class MethodReference {...//示例类public static class TestUtil {public static boolean isBiggerThan3(int input) {return input > 3;}public void printDetail(Student student) {System.out.println(student.toString());}}public static class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getStatus(String thing) {return String.format("%d岁的%s正在%s", age, name, thing);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}}
}

调用类的静态方法

Lambda表达式的那个单方法是某个类的静态方法

有如下格式,args是参数,可以是多个,例如(a1,a2,a3)

lambda:

(args) -> Class.staticMethod(args)

method reference

Class::staticMethod

符合上面形式的调用,不管有多少参数,都省略掉,编译器自动会帮我们传入

实例:

public void testStaticMethodRef() {//匿名内部类形式Predicate<Integer> p1 = new Predicate<Integer>() {@Overridepublic boolean test(Integer integer) {return TestUtil.isBiggerThan3(integer);}};//lambda表达式形式Predicate<Integer> p2 = integer -> TestUtil.isBiggerThan3(integer);//MethodReference形式Predicate<Integer> p3 = TestUtil::isBiggerThan3;Stream.of(1, 2, 3, 4, 5).filter(p3).forEach(System.out::println);
}

其中isBiggerThan3 是TestUtil类的static方法。从上面的代码你可以清晰的看到,方法从匿名类到Lambda再到方法引用的演变。

调用传入的实例参数的方法

lambda:

(obj, args) -> obj.instanceMethod(args)

method reference

ObjectType::instanceMethod

看到我们lambda的入参obj了吗?它是一个类型,假设为ObjectType,的实例对象。然后再看lambda表达式,是在调用此实例obj的方法。这种类型的lambda就可以写成上面的形式了,看起来和静态方法那个一样。

我们来举个栗子:

public void testInstanceMethodRef1() {//匿名类BiFunction<Student, String, String> f1 = new BiFunction<Student, String, String>() {@Overridepublic String apply(Student student, String s) {return student.getStatus(s);}};//lambdaBiFunction<Student, String, String> f2 = (student, s) -> student.getStatus(s);//method referenceBiFunction<Student, String, String> f3 = Student::getStatus;System.out.println(getStudentStatus(new Student("erGouWang", 18), "study", f3));
}
private String getStudentStatus(Student student, String action, BiFunction<Student, String, String> biFunction) {return biFunction.apply(student, action);
}

调用已经存在的实例的方法

lambda:

(args) -> obj.instanceMethod(args)

method reference

obj::instanceMethod

我们观察一下我们lambda表达式,发现obj对象不是当做参数传入的,而是已经存在的,所以写成方法引用时就是实例::方法.

举个栗子:

public void testInstanceMethodRef2() {TestUtil utilObj = new TestUtil();//匿名类Consumer<Student> c1 = new Consumer<Student>() {@Overridepublic void accept(Student student) {utilObj.printDetail(student);}};//Lambda表达式Consumer<Student> c2 = student -> utilObj.printDetail(student);//方法引用Consumer<Student> c3 = utilObj::printDetail;//使用consumeStudent(new Student("erGouWang", 18), c3);
}private void consumeStudent(Student student, Consumer<Student> consumer) {consumer.accept(student);
}

可见utilObj对象是我们提前new出来的,是已经存在了的对象,不是Lambda的入参。

调用类的构造函数

lambda:

(args) -> new ClassName(args)

method reference

ClassName::new

当lambda中的单方法是调用某个类的构造函数,我们就可以将其写成如上形式的方法引用

举个栗子

public void testConstructorMethodRef() {BiFunction<String, Integer, Student> s1 = new BiFunction<String, Integer, Student>() {@Overridepublic Student apply(String name, Integer age) {return new Student(name, age);}};//lambda表达式BiFunction<String, Integer, Student> s2 = (name, age) -> new Student(name, age);//对应的方法引用BiFunction<String, Integer, Student> s3 = Student::new;//使用System.out.println(getStudent("cuiHuaNiu", 20, s3).toString());
}private Student getStudent(String name, int age, BiFunction<String, Integer, Student> biFunction) {return biFunction.apply(name, age);
}

上面代码值得注意的就是,Student类必须有一个与lambda入参相匹配的构造函数。例如此例中,(name, age) -> new Student(name, age); 需要两个入参的构造函数,为什么呢?

因为我们的lambda表达式的类型是 BiFunction,而其正是通过两个入参来构建一个返回的。其签名如下:

@FunctionalInterface
public interface BiFunction<T, U, R> {R apply(T t, U u);...
}

通过入参(t,u)来生成R类型的一个值。

我们可以写一个如下的方法引用

Function<String, Student> s4 = Student::new;

但是IDE就会报错,提示我们的Student类没有对应的构造函数,我们必须添加一个如下签名的构造函数才可以

public Student(String name) {this.name = name;
}

总结

熟悉了以上四种类型后,方法引用再也难不住你了!留个作业:

Consumer<String> consumer1 = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}
};//lambda表达式
Consumer<String> consumer2 = ;//方法引用
Consumer<String> consumer3 = ;

 

http://www.jsqmd.com/news/691759/

相关文章:

  • React Native Modals测试策略:确保弹窗组件稳定性的完整方案
  • 嵌入式C语言与轻量大模型适配终极 checklist:12项硬性约束、5类编译器特异性陷阱、1次烧录即生效方案
  • 别再折腾串口了!实测QGC地面站RTK接入的正确姿势:USB直连保姆级教程
  • Transformer实战(27)——参数高效微调(Parameter Efficient Fine-Tuning,PEFT)
  • 2026年北京老房改造专业机构哪家好,多彩宜居装饰值得关注 - 工业品牌热点
  • 3种创新方法解决TranslucentTB开机启动难题
  • 保姆级攻略投票小程序永久免费使用
  • Win_ISO_Patching_Scripts项目中的WIM镜像修改时间功能问题分析
  • DLSS Swapper终极指南:免费工具轻松管理游戏DLSS版本,提升性能体验!
  • 如何用Python抢票脚本快速抢购大麦网演唱会门票:终极自动化抢票神器指南
  • uboot中调试景略phy JL3111A2-NA
  • 为什么叫向量嵌入
  • 武汉做社群团购商城选有赞,性价比高的公司是哪家? - 工业推荐榜
  • WebPlotDigitizer完整指南:3步从任何图表图像中提取精准数据
  • nli-MiniLM2-L6-H768候选重排序教程:提升搜索相关性,替代传统BM25二次精排
  • OnLogic CL260工业级无风扇迷你主机解析与应用
  • 大润发购物卡放着也是闲着,找个靠谱地方换成钱才香 - 团团收购物卡回收
  • 如何为create-react-app实现多语言支持:从零开始的国际化完整指南
  • Godot PCK文件解包终极指南:3种方法高效提取游戏资源
  • 2026想做全渠道私域找有赞服务,武汉靠谱公司Top10 - myqiye
  • Transformer实战(31)——解释Transformer模型决策
  • 华硕笔记本性能优化终极指南:用G-Helper告别卡顿,释放全部潜能![特殊字符]
  • 有哪些支持团购配送的板栗仁品牌,唐山凤凰人家好用吗 - 工业推荐榜
  • 如何高效限制ACE-Guard进程资源占用:sguard_limit完整使用指南
  • SyncTV OAuth2配置详解:集成Google、GitHub等第三方登录
  • 如何使用React Native Maps构建现代化农田管理和作物生长监测系统
  • 微信网页版访问技术范式:wechat-need-web的逆向工程实现机制
  • 向量嵌入(Embedding)概念及原理解析
  • 2026唐山有机板栗仁靠谱品牌推荐,满足你的品质需求 - myqiye
  • 3MF格式转换难题?Blender3mfFormat插件5步解决你的3D打印烦恼