方法引用介绍以及与lambda比较

写在最前:本文全程参考《Java核心技术卷I》,添加了一些个人的思考和整理。如有错误欢迎指出!

方法引用

1、方法引用的引入

假设你希望只要出现一个定时器时间,就打印这个对象,可以这么写:

var timer = new Timer(1000, event -> System.out.println(event));

但是,如果直接把println方法传递到Timer构造器就更好了。具体做法如下:

var timer = new Timer(1000, System.out::println);

表达式System.out::println是一个方法引用

它指示编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法来调用给定的方法。

方法引用通过方法的名字来指向一个方法。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

2、方法引用的用法

2.1 解释说明

var timer = new Timer(1000, System.out::println);中,System.out::println会用于构建一个ActionListener对象,它的actionPerformed(ActionEvent e)方法会调用System.out.println(e)

对于重载方法的选择,编译器会根据上下文确定要使用哪一个方法,上面对于ActionListener对象,编译器选择了pirntln(Object)方法,而对于Runnable task = System.out::println;,Runnable函数式接口有一个无参数的抽象方法void run(),编译器会选择无参数的println()方法

类似于lambda表达式,方法引用也不是一个对象。但是,为一个类型为函数式接口的变量赋值时会生成一个对象。运行时,方法引用最终都会转换为函数式接口的实例。

如果你相对字符串排序,而不考虑字母的大小写,可以传递以下表达式:

Arrays.sort(strings, String::compareToIgnoreCase);

2.2 方法引用的形式

  1. object::instanceMethod

    方法引用等价于想方法传递参数的lambda表达式。
    对于System.out::println而言,对象是System.out,方法表达式等价于x -> System.out.println(x)

  2. Class::instanceMethod

    第一个参数会成为方法的隐式参数。
    String::compareToIgnoreCase等同于(x,y) -> x.compareToIgnoreCase(y)

  3. Class::staticMethod

    所有参数都传递到静态方法中:Math::pow等价于(x,y) -> Math.pow(x,y)

  4. Class<T>::new

    传递一个构造器引用。具体可看本文第5节

2.3 使用示例

方法引用等价的lambda说明
separator::equalsx -> separator.equals(x)对象+实例方法
String::trimx -> x.trim()类+实例方法
Integer::concat(x, y) -> x.concat(y)类+实例方法
Integer::valueOf(x, y) -> Integer::valueOf(x)类+静态方法
Integer::sum(x, y) -> Integer::sum(x, y)类+静态方法
Integer::newx -> new Integer(x)构造器引用
Integer[]::newn -> new Integer[n]数组构造器引用

2.4 其他特点

方法引用可以使用thissuper关键字。this::equals等同于x -> this.equals(x)super::method可以传递父类的方法引用。

3、方法引用的使用示例

参考:菜鸟教程

4、方法引用和lambda的选择

只有当lambda表达式的体值调用一个方法而不做其他操作时,才能把lambda表达式重写为方法引用。
例如:s -> s.length() == 0包含了一个方法调用以及比较,所以不能使用方法引用。

5、构造方法引用

5.1 简介

Person::new就是Person的构造器引用。具体引用哪个构造器取决于上下文

5.2 泛型数组与数组构造函数引用

java无法构造泛型类型的数组,表达式new T[n]会出现错误,因为在编译时会因为泛型擦除而改为new Object[n]。使用方法引用就可以间接根据泛型构造数组

原因和做法可以参考我的另一篇博客:泛型篇笔记(二) 泛型底层原理——泛型擦除

现在,假设我们需要一个Person对象数组,Stream接口有一个toArray方法可以返回Object数组:Object[] people = stream.toArray();。不过,这样得到的结果仍是Object[]。而通过构造器引用就可以解决这个问题:

Person[] people = stream.toArray(Person::new);

toArray方法将通过这个构造器来创建一个正确类型的数组,然后填充并返回这个数组

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值