龙空技术网

java 核心技术-12版 卷Ⅰ- 6.2.4 方法引用

CC躺平混吃 70

前言:

如今我们对“java static method”大约比较关心,各位老铁们都想要剖析一些“java static method”的相关内容。那么小编也在网上汇集了一些有关“java static method””的相关资讯,希望你们能喜欢,咱们一起来了解一下吧!

原文6.2.4 方法引用

有时,lambda 表达式涉及一个方法。例如,假设你希望只要出现一个定时器事件就打印这个事件对象。当然,为此也可以调用:

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

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

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

表达式 System.out::printIn是一个方法引用(method reference),它指示编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法来调用给定的方法。在这个例子中,会生成一个ActionListener,它的actionPerformed(ActionEvent e) 方法要调用 System.out.println(e)。

注释:类似于lambda 表达式,方法引用也不是一个对象。不过,为一个类型为函数式接口的变量赋值时会生成一个对象。

注释:PrintStream类(System.out 就是PrintStream类的一个实例)中有10个重载的printIn 方法。编译器需要根据上下文确定使用哪一个方法。在我们的例子中,方法引用System.out::println 必须转换为一个包含以下方法的 ActionListener 实例;

void actionPerformed(ActionEvent e)

这样会从10个重载的printin方法中选出println(Object x)方法,因为Object与ActionEvent 最匹配。调用 actionPerformed 方法时,就会打印这个事件对象

​现在假设我们把同样的这个方法引用赋至一个不同的函数式接口:

Runnable task = System.out::printin;

这个 Runnable 函数式接口有一个无参数的抽象方法:

void run()

​在这种情况下,会选择无参数的 println() 方法。调用 task.run() 会向 System.out 打印一个空行。

​再来看一个例子,假设你想对字符串进行排序,而不考虑字母的大小写。可以传递以下方法表达式:

Arrays.sort(strings, String::compareToIgnoreCase)

从这些例子可以看出,要用 :: 操作符分隔方法名与对象或类名。主要有3 种情况

1. object::instanceMethod

2.Class::instanceMethod

3.Class::staticMethod

在第1种情况下,方法引用等价于一个lambda 表达式,其参数要传递到方法。对于System.out::println,对象是 System.out,所以这个方法表达式等价于x->System.out.println(x)。

对于第2种情况,第1个参数会成为方法的隐式参数。例如,String::compareToIgnoreCase

等同于(x,y)->x.compareTolgoreCase(y)

在第3种情况下,所有参数都传递到静态方法:Math::pow等价于(x,y) -> Math.pow(x,y)。

表6-1 提供了更多示例。注意、只有当lambda表达式的体只用一个方法而不做其他操作时,才能把 ambda表达式重写为方法引用。考虑以下 lambda 表达式:

s -> s.length() == 0;

这里有一个方法调用。但是还有一个比较、所以这里不能使用方法引用。

注释:如果有多个同名的重载方法,编译器就会尝试从上下文中找出你指的是哪一个方法。例如,Math.max 方法有两个版本,一个用于整数,另一个用于 double值。选择哪一个版本取决于Math::max 转换为哪个函数式接口的方法参数。类似于lambda 表达式,方法引用不会独立存在,总是会转接为函数式接口的实例。

注释:有时API包含一些专门用作方法引用的方法。例如,Objects 类有一个方法isNull,用于测试一个对象引用是否为null。乍看上去这好像没有什么用,因为测试obj== null比Objects.isNull(obj)更有可读性。不过可以把方法引用传递到任何有Predicate 参数的方法。例如,要从一个列表删除所有 null引用,就可以调用:

list.removelf(0bjects::isNull) ;

// A bit easier to read than list.removelf(e -> e = null);

注释: 包含对象的方法引用与等价的 lambda 表达式还有一个细微的差别。考虑一个方法引用,如 separator:: equals。如果 separator为null,构造 separator:: equals 时就会立即抛出一个NullPointerException 异常。而lambda表达式 x->separator.equals(x)只在调用时才会抛出 NullPointerException。

​可以在方法引用中使用 this参数。例如,this::equals 等同于x ->this.equals(x)。使用super 也是合法的。下面的方法表达式

super::instanceMethod

使用this 作为目标,会调用给定方法的超类版本。为了展示这一点,下面给出一个假想的例子:

class Greeter{	public void greet(ActionEvent event){    	System.out.println("hello , the time is "                          + Instant.ofEpochMilli(event.getWhen()));    }}class RepeatedGreeter extends Greeter{	public void greet(ActionEvent event){    	var timer = new Timer(1000, super::greet);      timer.start();    }}

RepeatedGreeter.greet 方法开始执行时,会构造一个Timer,每次定时器滴答时会执行super::greet 方法

标签: #java static method