文章目录
简单来说, 方法引用是针对接口来使用的。语法的一般形式为
xx::yy
,jre会自动推断实现的方法、参数列表以及返回值。这也就要求了接口必须带有
@FunctionalInterface
注解,或者符合
@FunctionalInterface
规范。
方法引用一共包含4中形式
|
|
---|---|
Reference to a static method | ContainingClass::staticMethodName |
Reference to an instance method of a particular object | containingObject::instanceMethodName |
Reference to an instance method of an arbitrary object of a particular type | ContainingType::methodName |
Reference to a constructor | ClassName::new |
Reference to a static method && Reference to an instance method of a particular object
这两个用法相似,放在一起写。
public class MethodRef {
public static void main(String[] args) {
IMethod iMethod1 = MethodRef::staticMethod;
IMethod iMethod2 = new MethodRef()::particularMethod;
}
public static void staticMethod(MethodRefTest test) {
}
public void particularMethod(MethodRefTest test) {
}
}
//Consumer
//@FunctionalInterface
interface IMethod{
void method(MethodRefTest test);
}
这两种写法分别相当于以staticMethod、particularMethod作为实现方法去生成一个匿名实现类。与下方代码等效
public class MethodRef {
public static void main(String[] args) {
IMethod iMethod1 = MethodRef::staticMethod;
IMethod iMethod2 = new MethodRef()::particularMethod;
IMethod iMethod3 = new IMethod() {
@Override
public void method(MethodRefTest test) {
// TODO Auto-generated method stub
MethodRef.staticMethod(test);
}
};
IMethod iMethod4 = new IMethod() {
@Override
public void method(MethodRefTest test) {
// TODO Auto-generated method stub
new MethodRef().particularMethod(test);
}
};
}
public static void staticMethod(MethodRefTest test) {
}
public void particularMethod(MethodRefTest test) {
}
}
//Consumer
//@FunctionalInterface
interface IMethod{
void method(MethodRefTest test);
}
可以看出,这个语法的关键点只在于实现方法的参数列表与返回值,只要这两点一致,那么,不管方法写在了哪个类中,都可以使用。
Reference to an instance method of an arbitrary object of a particular type
关于这种写法,我一直没有找到什么太好的解释。只是从形式上看,它与第二种写法的主要区别就是,允许参数列表不同,jre会自动的向下寻找合适的方法来执行。由于推断的规则的原因,所使用的接口必须使用泛型。
见下例中method5
public class MethodRef {
public static void main(String[] args) {
IMethod iMethod1 = MethodRef::staticMethod;
IMethod iMethod2 = new MethodRef()::particularMethod;
IMethod iMethod3 = new IMethod() {
@Override
public void method(MethodRefTest test) {
// TODO Auto-generated method stub
MethodRef.staticMethod(test);
}
};
IMethod iMethod4 = new IMethod() {
@Override
public void method(MethodRefTest test) {
// TODO Auto-generated method stub
new MethodRef().particularMethod(test);
}
};
IMethod2<MethodRef> iMethod5 = MethodRef::noVar;
}
public static void staticMethod(MethodRefTest test) {
}
public void particularMethod(MethodRefTest test) {
}
public IMethod noVar() {
return (p) -> {};
}
}
//Consumer
//@FunctionalInterface
interface IMethod{
void method(MethodRefTest test);
}
interface IMethod2<T>{
void method(T test);
}
jre会自动推断出合适的方法来执行,但是,到底什么是合适,我目前还没有找到像样的解释。
Reference to a constructor
与上一种相似,也是必须要使用泛型。但是我目前只找到了适用于类似Supplier
接口的例子,感觉用处不是很大。
例(见下方代码iMethod6,iMethod7)
import java.util.function.Supplier;
public class MethodRef {
public static void main(String[] args) {
IMethod iMethod1 = MethodRef::staticMethod;
IMethod iMethod2 = new MethodRef()::particularMethod;
IMethod iMethod3 = new IMethod() {
@Override
public void method(MethodRefTest test) {
// TODO Auto-generated method stub
MethodRef.staticMethod(test);
}
};
IMethod iMethod4 = new IMethod() {
@Override
public void method(MethodRefTest test) {
// TODO Auto-generated method stub
new MethodRef().particularMethod(test);
}
};
IMethod2<MethodRef> iMethod5 = MethodRef::noVar;
IMethod3<MethodRef> iMethod6 = MethodRef::new;
Supplier<MethodRef> iMethod7 = MethodRef::new;
}
public static void staticMethod(MethodRefTest test) {
}
public void particularMethod(MethodRefTest test) {
}
public IMethod noVar() {
return (p) -> {};
}
}
//Consumer
//@FunctionalInterface
interface IMethod{
void method(MethodRefTest test);
}
interface IMethod2<T>{
void method(T test);
}
//形式与Supplier相似
interface IMethod3<T>{
T method();
}
参考文档
官方文档地址
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
参考帖子
Java 8 constructor method references
Reference to an instance method of an arbitrary object of a particular type… not working with custom classes?
官方例子
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle or the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Collection;
import java.util.function.Supplier;
import java.util.Set;
import java.util.HashSet;
import java.time.LocalDate;
import java.time.chrono.IsoChronology;
public class MethodReferencesTest {
// The method transferElements copies elements from one collection to
// another
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;
}
public static void main(String... args) {
List<Person> roster = Person.createRoster();
for (Person p : roster) {
p.printPerson();
}
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());
}
}
// Without method reference
Arrays.sort(rosterAsArray, new PersonAgeComparator());
// With lambda expression
Arrays.sort(rosterAsArray,
(Person a, Person b) -> {
return a.getBirthday().compareTo(b.getBirthday());
}
);
// With method reference
Arrays.sort(rosterAsArray, Person::compareByAge);
// 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);
// 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);
Set<Person> rosterSetLambda =
transferElements(roster, () -> { return new HashSet<>(); });
Set<Person> rosterSet = transferElements(
roster, HashSet::new);
System.out.println("Printing rosterSet:");
rosterSet.stream().forEach(p -> p.printPerson());
}
}
class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthday;
Sex gender;
String emailAddress;
Person(String nameArg, LocalDate birthdayArg,
Sex genderArg, String emailArg) {
name = nameArg;
birthday = birthdayArg;
gender = genderArg;
emailAddress = emailArg;
}
public int getAge() {
return birthday
.until(IsoChronology.INSTANCE.dateNow())
.getYears();
}
public void printPerson() {
System.out.println(name + ", " + this.getAge());
}
public Sex getGender() {
return gender;
}
public String getName() {
return name;
}
public String getEmailAddress() {
return emailAddress;
}
public LocalDate getBirthday() {
return birthday;
}
public static int compareByAge(Person a, Person b) {
return a.birthday.compareTo(b.birthday);
}
public static List<Person> createRoster() {
List<Person> roster = new ArrayList<>();
roster.add(
new Person(
"Fred",
IsoChronology.INSTANCE.date(1980, 6, 20),
Person.Sex.MALE,
"fred@example.com"));
roster.add(
new Person(
"Jane",
IsoChronology.INSTANCE.date(1990, 7, 15),
Person.Sex.FEMALE, "jane@example.com"));
roster.add(
new Person(
"George",
IsoChronology.INSTANCE.date(1991, 8, 13),
Person.Sex.MALE, "george@example.com"));
roster.add(
new Person(
"Bob",
IsoChronology.INSTANCE.date(2000, 9, 12),
Person.Sex.MALE, "bob@example.com"));
return roster;
}
}