首页 > java > jdk8 > 6.JDK8方法引用

6.JDK8方法引用

jdk8.0引入了方法引用的概念.

1 java方法引用的概念

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

看下面这个Person类:

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()]);//可认为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)在语义上是等价的.

两者有如下的共同点:

1.形参相同.都是(Person, Person). 2.调用方法Person.compareByAge.

2 java方法引用的种类

类型 示例
类静态方法引用 ContainingClass::staticMethodName
某个对象的方法引用 ContainingObject::instanceMethodName
特定类的任意对象的方法引用 ContainingType::methodName
构造方法引用 ClassName::new

2.1 java静态方法引用

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

2.2 java某个对象的方法引用

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

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

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

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) 方法执行.

2.4 java构造方法引用

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

3 参考文章

http://blog.csdn.net/wwwsssaaaddd/article/details/37573517

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

转载请保留原文链接.