java8 之方法引用

方法引用

你可以使用lambda表达式来创建匿名方法。 但是,有时,lambda表达式只是仅仅调用一个方法。在这些情况下,通过方法名称调用现有方法会更清楚得表达意思。java8得方法引用现在允许你这样做,对于已有名称的方法,方法引用是紧凑的,易于阅读的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得数组,你希望通过年龄Age来排序,代码请参考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());

方法sort的方法签名如下:

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

我们发现Comparator一个 functional interface接口,因此,我们应该使用lambda表达式,而不是定义然后创建实现Comparator的接口的新实例。

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

但是,这种比较两个Person实例的birthday的方法,我们已经在Person类中定义了Person.compareByAge方法。 你可以在lambda表达式的主体中调用此方法:

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

因为此lambda表达式只是调用已有得方法,所以可以使用方法引用而不是lambda表达式:

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

方法引用 Person::compareByAge 在语义上与 lambda 表达式 (a, b) -> Person.compareByAge(a, b)相同.

方法引用得种类

方法引用主要有四类。

种类格式例子
指向静态方法得方法引用ContainingClass::staticMethodNameInteger::parseInt
指向任意类型实例方法得方法引用ContainingType::methodNameString::length
指向现有对象的实例方法得方法引用containingObject::instanceMethodNameperson::getEmailAddress
指向构造函数ClassName::newPerson::new
指向静态方法得方法引用

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

指向任意类型实例方法得方法引用

引用示例:

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

方法引用 String::compareToIgnoreCase 等效的lambda表示式为:

(String a,String b)-> a.compareToIgnoreCase(b)
  Arrays.sort(stringArray, (a, b) -> {
        return Person.compareByAge(a, b);
    });
指向现有对象的实例方法得方法引用

引用示例:

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

指向构造函数

引用示例:

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

functional interface Supplier含有一个get方法,不带参数,且有返回值。因此,你可以使用lambda表达式来调用transferElements方法,如下所示:

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

你也可以使用构造函数方法引用代替lambda表达式,如下所示:

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

Java编译器推断你要创建包含Person类型的HashSet集合。 或者,你也可以按如下方式指定:

Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值