java8 - 方法引用(method referrance)

时间:2021-02-02 05:33:41

方法引用的概念

       某些lambda表达式里面仅仅是执行一个方法调用。在这种情况下,不用lambda表达式,直接通过方法名称引用方法的形式可读性更高一些,这种形式就是方法引用,方法引用是一种更简洁易懂的lambda 表达式。

看下面这个Person类:

public class Person {

       public enum Sex {

              MALEFEMALE

       }

       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()]);//可认为roster是你好友的名册

class PersonAgeComparator implements Comparator<Person> {

public int compare(Person a, Person b) {

        return a.getBirthday().compareTo(b.getBirthday());

    }

}

Arrays.sort(rosterAsArray, new PersonAgeComparator());

sort方法定义如下:

static <T> void sort(T[] a, Comparator<? super T> c)

       注意Comparator接口是一个函数接口。 因此,这里可以使用lambda表达式,省去了定义PersonAgeComparator 类和创建一个类实例,如下。

Arrays.sort(rosterAsArray,

    (Person a, Person b) -> {

        return a.getBirthday().compareTo(b.getBirthday());

    }

);

       然而, 比较两个Person对象的生日大小的方法Person.compareByAge,已经在Person类中定义了。 这样,在lambda表达式主体内直接调用Person.compareByAge就好了:

Arrays.sort(rosterAsArray,

    (a, b) -> Person.compareByAge(a, b)

);

       因为上面的lamdba表达式调用了一个现成的方法,所以可以用方法引用替代这个lamdba表达式:

Arrays.sort(rosterAsArray,

   Person::compareByAge

);

       方法引用Person::compareByAge跟lambda表达式(a, b) -> Person.compareByAge(a,b)在语义上是等价的。 两者有如下的特征 :

·   形参相同 ,都是(Person, Person)。

·   调用方法Person.compareByAge。

方法引用的种类

一共有四种类型的方法引用:

类型

示例

类静态方法引用

ContainingClass::staticMethodName

某个对象的方法引用

ContainingObject::instanceMethodName

特定类的任意对象的方法引用

ContainingType::methodName

构造方法引用

ClassName::new

1)静态方法引用

方法引用Person::compareByAge 就是对一个静态方法引用。

2)某个对象的方法引用

下面就是一个对特定对象的实例方法引用的例子:

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

这个方法引用 myComparisonProvider::compareByName 调用了myComparisonProvider对象的compareByName方法。JRE 会推断出方法的类型参数,比如在这个例子中是(Person, Person)。

3)特定类的任意对象的方法引用

String[]stringArray = { "Barbara""James""Mary""John",

    "Patricia""Robert""Michael""Linda" };

Arrays.sort(stringArray, String::compareToIgnoreCase);

       与这个方法引用String::compareToIgnoreCase等价的lambda表达式要有形参列表(String a, String b),此处a和b是随意取的名字。这个方法引用将会触发a.compareToIgnoreCase(b) 方法执行。

4)构造方法引用

       使用new关键词引用构造方法就像引用类静态方法一样。下面方法实现了从一个集合复制其元素到另一个集合中:

public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>

    DEST transferElements(

        SOURCEsourceCollection,

        Supplier<DEST>collectionFactory) {

      DESTresult = collectionFactory.get();

        for (T t : sourceCollection) {

           result.add(t);

        }

        return result;

}

       函数接口Supplier有一个方法get,get无输入参数,输出是一个对象。这样,你可以使用一个lambda 表达式调用transferElements方法,如下所示:

Set<Person>rosterSetLambda =

    transferElements(roster, () -> { return new HashSet<>(); });

       进一步,你可以使用构造方法引用来替代lambda 表达式:

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

       Java编译器推断出你想创建一个HashSet集合,其中包含Person类型的元素。当然,你也可以像下面这样显式的指定集合元素的类型为Person

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

 

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