程序员

Lambda之方法的引用

2016-06-07  本文已影响0人  巡山的喽罗

Lambda创建一个匿名方法,这提供了一种比拥有一个方法的匿名类更简洁的用法。如果说Lambda简单到只需要调用一个现有的方法,那么方法引用可以作为一个Lambda表达式来让代码变的更加简洁直观。

方法是可以引用的

回顾初识Lambda当中介绍的场景,现在管理员需要用户按照生日进行排序,Lambda可以简洁直观的完成这个场景。


List<Person> roster = Person.createRoster();
Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);
Arrays.sort(rosterAsArray,
    (a, b) -> {
        return a.getBirthday().compareTo(b.getBirthday());
    }
);

由于Person提供了一个静态方法compareByAge,这个方法简化排序算法的代码。


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

但这并不是最干净的方式,借助方法引用可以更加简单。


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

Person::compareByAge完全等同于(a, b) -> { return Person.compareByAge(a, b); }
因为Lambda表达式仅仅使用到了一个简单的方法,所以可以借助方法引用这个特性直接将这个方法作为Lambda表达式使用。

哪类方法可以引用

类型 使用方式
静态方法 ContainingClass::staticMethodName
指定实例的方法 containingObject::instanceMethodName
特定类实例的任意方法 ContainingType::methodName
构造方法 ClassName::new

静态方法

正如之前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);

特定类实例的任意方法

这个用法与上面相比稍微特殊一些。


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

可以看到sort操作的对象是String数组,compareToIgnoreCase既不是静态方法,同时也没有通过使用一个String对象的方法引用,而是直接将StringcompareToIgnoreCase方法作为Lambda。compareToIgnoreCase实际只有一个输入参数,Lambda的目标类型Compartor<T>compare(T o1, T o2)是有两个输入参数的,按照之前的方式,这个引用的方法似乎也是需要两个String类型的参数。
其实并非如此,虽然Lambda有两个输入参数,这两个输入参数可以看做是ab,方法的引用则与a.compareToIgnoreCase(b)这种调用方式相同。

构造方法

定义了一个可以转换集合实现方式的方法,这个方法可以将一种集合对象转换成另外一种集合对象。


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

其中的Supplier是一个JDK标准函数接口,它提供了一个get的无参方法,这里通过get构造了一个Set实例。如果把一个List集合转换成Set集合,使用Lambda实现:


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

通过构造方法的引用变的更简洁。


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

编译器可以推断出HashSet的类型参数,也可以显式声明类型参数。


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


参考资料

  1. Java Tutorials Learning Paths - Method References
上一篇下一篇

猜你喜欢

热点阅读