方法引用
You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it’s often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.
Consider again the Person
class discussed in the section Lambda Expressions:
使用lambda表达式创建匿名方法。然而,有时lambda表达式除了调用现有方法外什么也不做。在这些情况下,通过名称引用现有方法通常会更清楚。方法引用使您能够做到这一点;对于已有名称的方法,它们是紧凑、易于阅读的lambda表达式。
再次考虑lambda表达式一节中讨论的Person类
public class Person {
// ...
LocalDate birthday;
public int getAge() {
// ...
}
public LocalDate getBirthday() {
return birthday;
}
public static int compareByAge(Person a, Person b) {
return a.birthday.compareTo(b.birthday);
}
// ...
}
Suppose that the members of your social networking application are contained in an array, and you want to sort the array by age. You could use the following code (find the code excerpts described in this section in the example MethodReferencesTest
):
假设你的社交网络应用程序的成员包含在一个数组中,你想按年龄对数组排序。你可以使用以下代码(在示例MethodReferencesTest
中找到本节描述的代码摘录):
Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);
class PersonAgeComparator implements Comparator<Person> {
public int compare(Person a, Person b) {
return a.getBirthday().compareTo(b.getBirthday());
}
}
Arrays.sort(rosterAsArray, new PersonAgeComparator());
The method signature of this invocation of sort
is the following:
’ sort '调用的方法签名如下:
static <T> void sort(T[] a, Comparator<? super T> c)
Notice that the interface Comparator
is a functional interface. Therefore, you could use a lambda expression instead of defining and then creating a new instance of a class that implements Comparator
:
请注意,Comparator
接口是一个函数式接口。因此,你可以使用lambda表达式,而不是定义然后创建一个实现Comparator
的类的新实例:
Arrays.sort(rosterAsArray,
(Person a, Person b) -> {
return a.getBirthday().compareTo(b.getBirthday());
}
);
However, this method to compare the birth dates of two Person
instances already exists as Person.compareByAge
. You can invoke this method instead in the body of the lambda expression:
然而,这种比较两个Person
实例出生日期的方法已经存在,即Person. comparebyage
。你可以在lambda表达式的主体中调用这个方法:
Arrays.sort(rosterAsArray,
(a, b) -> Person.compareByAge(a, b)
);
Because this lambda expression invokes an existing method, you can use a method reference instead of a lambda expression:
因为这个lambda表达式会调用一个已经存在的方法,所以你可以使用方法引用来代替lambda表达式:
Arrays.sort(rosterAsArray, Person::compareByAge);
The method reference Person::compareByAge
is semantically the same as the lambda expression (a, b) -> Person.compareByAge(a, b)
. Each has the following characteristics:
- Its formal parameter list is copied from
Comparator<Person>.compare
, which is(Person, Person)
. - Its body calls the method
Person.compareByAge
.
方法引用Person::compareByAge
在语义上与lambda表达式(a, b) -> Person.compareByAge(a, b)
。它们都有以下特点:
-它的形式参数列表是从 Comparator<Person>.compare
复制过来的,它是(Person, Person)
。
-它的主体调用了Person.compareByAge
方法。
方法引用的种类
There are four kinds of method references:
有四种方法引用:
Kind | Syntax | Examples |
---|---|---|
Reference to a static method指向静态方法的引用 | *ContainingClass*::*staticMethodName* | Person::compareByAge MethodReferencesExamples::appendStrings |
Reference to an instance method of a particular object引用特定对象的实例方法 | *containingObject*::*instanceMethodName* | myComparisonProvider::compareByName myApp::appendStrings2 |
Reference to an instance method of an arbitrary object of a particular type引用特定类型任意对象的实例方法 | *ContainingType*::*methodName* | String::compareToIgnoreCase String::concat |
Reference to a constructor对构造函数的引用 | *ClassName*::new | HashSet::new |
The following example, MethodReferencesExamples
, contains examples of the first three types of method references:
下面的例子,MethodReferencesExamples
,包含了前三种类型的方法引用:
import java.util.function.BiFunction;
public class MethodReferencesExamples {
public static <T> T mergeThings(T a, T b, BiFunction<T, T, T> merger) {
return merger.apply(a, b);
}
public static String appendStrings(String a, String b) {
return a + b;
}
public String appendStrings2(String a, String b) {
return a + b;
}
public static void main(String[] args) {
MethodReferencesExamples myApp = new MethodReferencesExamples();
// Calling the method mergeThings with a lambda expression
System.out.println(MethodReferencesExamples.
mergeThings("Hello ", "World!", (a, b) -> a + b));
// Reference to a static method
System.out.println(MethodReferencesExamples.
mergeThings("Hello ", "World!", MethodReferencesExamples::appendStrings));
// Reference to an instance method of a particular object
System.out.println(MethodReferencesExamples.
mergeThings("Hello ", "World!", myApp::appendStrings2));
// Reference to an instance method of an arbitrary object of a
// particular type
System.out.println(MethodReferencesExamples.
mergeThings("Hello ", "World!", String::concat));
}
}
All the System.out.println()
statements print the same thing: Hello World!
BiFunction
is one of many functional interfaces in the java.util.function
package. The BiFunction
functional interface can represent a lambda expression or method reference that accepts two arguments and produces a result.
所有System.out.println()
语句输出相同的内容:’ Hello World!`
BiFunction
是java.util.function
包中的函数式接口之一。BiFunction
函数接口可以表示一个接受两个参数并产生结果的lambda表达式或方法引用。
引用静态方法
The method references Person::compareByAge
and MethodReferencesExamples::appendStrings
are references to a static method.
方法引用Person::compareByAge
和MethodReferencesExamples::appendStrings
是对一个静态方法的引用。
引用特定对象的实例方法
The following is an example of a reference to an instance method of a particular object:
下面是一个引用特定对象的实例方法的例子:
class ComparisonProvider {
public int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
public int compareByAge(Person a, Person b) {
return a.getBirthday().compareTo(b.getBirthday());
}
}
ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
The method reference myComparisonProvider::compareByName
invokes the method compareByName
that is part of the object myComparisonProvider
. The JRE infers the method type arguments, which in this case are (Person, Person)
.
Similarly, the method reference myApp::appendStrings2
invokes the method appendStrings2
that is part of the object myApp
. The JRE infers the method type arguments, which in this case are (String, String)
.
方法引用myComparisonProvider::compareByName
调用了compareByName
方法,该方法是对象myComparisonProvider
的一部分。JRE推断出方法的类型参数,在本例中为(Person, Person)
。
类似地,方法引用myApp::appendStrings2
会调用对象myApp
中的appendStrings2
方法。JRE推断方法类型参数,在本例中为(String, String)
。
对特定类型任意对象的实例方法的引用
The following is an example of a reference to an instance method of an arbitrary object of a particular type:
下面是对特定类型的任意对象的实例方法的引用示例:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
The equivalent lambda expression for the method reference String::compareToIgnoreCase
would have the formal parameter list (String a, String b)
, where a
and b
are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b)
.
Similarly, the method reference String::concat
would invoke the method a.concat(b)
.
方法引用String::compareToIgnoreCase
等效的lambda表达式具有正式的参数列表(String a, String b)
,其中a
和b
是为了更好地描述这个示例而使用的任意名称。方法引用将调用方法a.compareToIgnoreCase(b)
。
类似地,方法引用String::concat
将调用方法a.concat(b)
。
对构造函数的引用
You can reference a constructor in the same way as a static method by using the name new
. The following method copies elements from one collection to another:
你可以像引用静态方法一样使用new
来引用构造函数。下面的方法将元素从一个集合复制到另一个集合:
public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
DEST transferElements(
SOURCE sourceCollection,
Supplier<DEST> collectionFactory) {
DEST result = collectionFactory.get();
for (T t : sourceCollection) {
result.add(t);
}
return result;
}
The functional interface Supplier
contains one method get
that takes no arguments and returns an object. Consequently, you can invoke the method transferElements
with a lambda expression as follows:
函数式接口Supplier
包含一个没有参数并返回一个对象的方法get
。因此,你可以使用lambda表达式调用transferElements
方法,如下所示:
Set<Person> rosterSetLambda =
transferElements(roster, () -> { return new HashSet<>(); });
You can use a constructor reference in place of the lambda expression as follows:
你可以使用构造函数引用来代替lambda表达式,如下所示:
Set<Person> rosterSet = transferElements(roster, HashSet::new);
The Java compiler infers that you want to create a HashSet
collection that contains elements of type Person
. Alternatively, you can specify this as follows:
Java编译器推断出你想要创建一个包含类型为Person
的元素的HashSet
集合。或者,你也可以这样指定:
Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);
翻译自Oracle官网的java文档教程,原文链接:https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html