Java8 - Method Reference

什么是method reference

  • 通常我们可以用lambda表达式去创建一个匿名方法,然而有的时候,一个lambda表达式什么都不做只是调用一个已经存在的方法,这种情况下,我们可以使用一个更紧凑易读的方式去表达就是method reference ::
  • 我们调用的这个方法可以是静态方法也可以是实例方法
  • 我们调用的这个方法要求跟Function Interface里面的方法有同样的参数变量,但是其他的比如返回类型,方法名称,方法修饰符是不要求一样的

Method Reference的类型

类型 例子
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

类型1: 引用static method

语法: Classname::methodName
举例:

public class Person {

    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        // ...
    }
    
    public Calendar getBirthday() {
        return birthday;
    }    

    public static int compareByAge(Person a, Person b) {
        return a.birthday.compareTo(b.birthday);
    }}
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());

这里Comparator是个Functional Interface所以我们可以写成Lambda表达式:


Arrays.sort(rosterAsArray, (Person a, Person b) -> {return a.getBirthday().compareTo(b.getBirthday());});

然而比较生日的方法已经在Person类里面定义了,所以我们可以简单的写成:

Arrays.sort(rosterAsArray, ( a, b) -> Person.compareByAge(a,b););

因为Lambda表达式调用了一个已经存在的方法,所以我们可以用method reference来代替Lambda表达式

Arrays.sort(rosterAsArray, Person::compareByAge);

method reference Person::compareByAge 跟 lambda 表达式(a, b) -> Person.compareByAge(a, b) 是一样的. method reference的参数来自 Comparator<Person>.compare, 就是 (Person, Person).方法内容本身来自 Person.compareByAge.

类型:引用实例方法


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);

我们再看个例子:

//首先定义个Functional Interface
interface interf{
    void m1(int i);
}

Class Test{
    public void m2(int i) { 
       System.out.println("From Method Reference:"+i);
    }
    public static void main(String[] args){
        interf inter1 = i -> System.out.println("From Lambda expression:"+i);
        inter1.m1(10);
        Test test = new Test();
        Interf inter2 =test:m2;
        inter2.m1(20);
    }
}

在上面这个例子中,我们实现的是接口里的方法m1()直接引用Test类里面的实例方法m2().
这里的主要的优势是我们可以重用已经存在的方法去实现interface,轻易的达到代码重用

任意对象的实例方法引用

String[] stringArray = { "Barbara", "James", "Mary", "John",
    "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

这里的compareToIgnoreCase是个实例方法,不是静态方法,所以String::compareToIgnoreCase 相当于任意定义了两个变量 (String a, String b), 然后调用了a.compareToIgnoreCase(b).

调用构造函数

我们可以调用构造函数, 用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;
}

Set<Person> rosterSetLambda =
    transferElements(roster, () -> { return new HashSet<>(); });

这里我们可以用method reference:

Set<Person> rosterSet = transferElements(roster, HashSet::new);

Java编译器推断出,你想创建一个包含Person类型的HashSet集合,或者你也可以写成如下:

Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);

Referece:

https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容