Java 8 方法引用

2025年1月11日 | 阅读 8 分钟

Java 8 提供了一个名为方法引用的新特性。方法引用是指向函数式接口的一个方法。它是 lambda 表达式的一种简洁易懂的形式。当我们使用 lambda 表达式引用一个方法时,可以将其替换为方法引用。本节将详细解释方法引用的概念。

方法引用类型

Java 中有以下几种方法引用类型:

  1. 指向静态方法的引用。
  2. 指向特定对象实例方法的引用。
  3. 指向构造函数的引用。
  4. 指向特定类型任意对象实例方法的引用。
Types of Java Method References

1) 指向静态方法的引用

我们可以引用类中定义的静态方法。以下是引用 Java 中静态方法的语法和示例,它描述了该过程。

语法

示例 1

在下面的示例中,我们定义了一个函数式接口,并将其函数式方法 say() 引用到一个静态方法。

文件名:MethodReference.java

输出

Hello, this is static method.

解释

提供的代码展示了如何在 Java 中使用方法引用。它为 Sayable 接口定义了一个单一的抽象方法 say()。MethodReference 类的静态函数 saySomething() 打印一条消息。在 main() 方法中,使用 Sayable 函数式接口的方法引用语法 (MethodReference::saySomething) 来引用静态方法 saySomething()。最终,调用 Sayable 接口的 say() 函数,该函数将 "Hello, this is static method." 打印到控制台并调用静态的 saySomething() 方法。

示例 2

在下面的示例中,我们使用了预定义的函数式接口 Runnable 来引用静态方法。

文件名:MethodReference2.java

输出

Thread is running...

解释

代码中定义了一个名为 MethodReference2 的类,其静态方法 ThreadStatus() 将 "Thread is running..." 打印到控制台。在 main() 方法中,通过提供对静态方法 ThreadStatus() 的引用,使用方法引用语法 (MethodReference2::ThreadStatus) 创建了一个新的 Thread 对象 t2。然后通过调用 t2 线程对象的 start() 方法来启动 ThreadStatus() 方法,使其在另一个线程中运行。这说明了如何使用方法引用在新的线程上下文中运行静态方法。

示例 3

我们也可以使用预定义的函数式接口来引用方法。在下面的示例中,我们使用了 BiFunction.apply() 方法。

文件名:MethodReference3.java

输出

30

解释

下面的代码演示了如何使用 Java 的方法引用与函数式接口。首先,在名为 Arithmetic 的类中定义了一个名为 add() 的静态函数,它接受两个整数参数并返回它们的和。然后,MethodReference3 类的 main() 方法展示了如何使用方法引用与 BiFunction 函数式接口。

BiFunction 表示一个接受两个参数并返回一个结果的函数。此实例使用方法引用语法 (Arithmetic::add) 来引用 Arithmetic 类的 add() 函数。然后使用 adder BiFunction 将 add() 方法应用于参数 10 和 20,产生一个和。

最后,计算出的结果显示在终端上。这说明了方法引用如何简化函数式接口的使用,提高代码的可读性和简洁性。

示例 4

我们也可以通过引用方法来重载静态方法。在下面的示例中,我们定义并重载了三个 add 方法。

文件名:MethodReference4.java

输出

30
30.0
30.0

解释

提供的代码演示了如何使用 Java 的方法引用和重载。它引入了一个名为 Arithmetic 的类,该类有三个重载的静态 add() 方法。这些方法接受各种浮点数和整数参数的组合,返回它们的总和,并接受这些参数。

在 MethodReference4 类中,使用方法引用语法创建了三个 BiFunction 实例,每个实例都引用 Arithmetic 类的匹配的重载的 add() 函数。然后,main() 方法使用这些 BiFunction 实例计算整数和浮点值的总和,演示了使用方法引用进行方法重载。最后,计算出的结果显示在终端上。这说明了方法引用如何通过使在函数式接口中调用重载方法变得更容易,从而提高代码的可读性和简洁性。

2) 指向实例方法的引用

与静态方法一样,我们也可以引用实例方法。在下面的示例中,我们描述了引用实例的过程。

语法

示例 1

在下面的示例中,我们引用的是非静态方法。我们可以通过类对象和匿名对象来引用方法。

文件名:InstanceMethodReference.java

输出

Hello, this is non-static method.
Hello, this is non-static method.

解释

提供的 Java 代码展示了如何使用实例方法引用。它为 Sayable 接口定义了一个单一的抽象方法 say()。InstanceMethodReference 类的非静态方法 saySomething() 打印一条消息。在 main() 方法中创建了 InstanceMethodReference 类的一个实例。

接下来,将 Sayable 函数式接口赋给非静态方法 saySomething(),该方法使用方法引用语法 (methodReference::saySomething) 进行引用。最终,调用 Sayable 接口的 say() 方法,该方法将 "Hello, this is a non-static method." 打印到控制台并调用 saySomething() 非静态函数。

示例 2

在下面的示例中,我们引用的是实例(非静态)方法。Runnable 接口只包含一个抽象方法。因此,我们可以将其用作函数式接口。

文件名:InstanceMethodReference2.java

输出

Hello, this is instance method

解释

此 Java 代码中定义的 InstanceMethodReference2 类中的非静态方法 printnMsg() 将 "Hello, this is instance method" 打印到控制台。在 main() 方法中创建了一个名为 t2 的新 Thread 对象,其构造函数使用方法引用语法 (new InstanceMethodReference2()::printnMsg) 来获取对新构造的 InstanceMethodReference2 实例的 printnMsg() 方法的引用。

这启动了一个线程,该线程在运行时将使用 printnMsg() 函数。最后,通过调用 t2 线程对象的 start() 方法来启动 printnMsg() 函数,该函数在另一个线程上将消息打印到控制台。这说明了如何使用实例方法引用在新的线程上下文中运行非静态方法。

示例 3

在下面的示例中,我们使用 BiFunction 接口。这是一个预定义的接口,包含一个函数式方法 apply()。在这里,我们将 add 方法引用到 apply 方法。

文件名:InstanceMethodReference3.java

输出

30

解释

此 Java 代码中的 Arithmetic 类的非静态函数 add() 接受两个整数参数并返回它们的和。在 InstanceMethodReference3 类的 main() 方法中,创建了一个名为 adder 的 BiFunction 实例。它使用实例方法引用语法 (new Arithmetic()::add) 来引用新构造的 Arithmetic 类的实例的 add() 函数。

这样,BiFunction 和 add() 方法就被绑定在一起,允许 BiFunction 使用两个整数参数进行调用并返回它们的和。最后,为了说明如何使用实例方法引用与函数式接口进行方法调用,对 adder 函数使用参数 10 和 20 调用 apply() 方法,并将结果打印到控制台。

3) 指向构造函数的引用

我们可以使用 new 关键字来引用构造函数。在这里,我们借助函数式接口来引用构造函数。

语法

示例

文件名:ConstructorReference.java

输出

Hello

解释

代码演示了 Java 中构造函数引用的使用。Messageable 接口上的 getMessage() 函数返回 Message 类的实例。Message 类的构造函数将一条消息打印到控制台。在 ConstructorReference 类的 main() 方法中,使用构造函数引用语法 (Message::new) 来引用 Message 类的构造函数,从而创建一个名为 hello 的 Messageable 实例。

然后,当使用字符串参数 "Hello" 调用 hello 的 getMessage() 函数时,会创建一个新的 Message 对象,并将消息打印到控制台。这表明使用构造函数引用可以简单而简洁地在函数式接口内实例化对象。

4) 指向特定类型任意对象实例方法的引用。

在 Java 中引用对象或类的方法的一种清晰技术是使用方法引用。一种特殊的方法引用是针对给定类型任意对象的实例方法的引用。它使我们能够调用实例方法,而无需显式命名给定类型对象上的对象。

文件名:MethodReferenceExample.java

输出

[Alice, Bob, Charlie, David]
[Alice, Bob, Charlie, David]

解释

提供的 Java 示例展示了如何使用 lambda 表达式和方法引用对字符串列表进行不区分大小写的排序。首先,使用 lambda 表达式 (String s1, String s2) -> s1 对列表进行排序。要定义一个自定义的比较器来进行不区分大小写的排序,请使用 compareToIgnoreCase(s2)。然后使用方法引用 String::compareToIgnoreCase,它提供了 lambda 表达式的更简洁的替代方案。

使用此方法引用可以简化排序,该方法直接调用 String 类的 compareToIgnoreCase() 方法。两种方法都产生相同的结果,即排序后的字符串列表显示在控制台上。这说明了 Java 方法引用的灵活性和可读性,尤其是在处理比较器等函数式接口时。


下一个主题Java 8 函数式接口