深入理解Java8双冒号::的使用

网友投稿 341 2022-11-21


深入理解Java8双冒号::的使用

一、方法引用

java8允许我们使用lambda表达式创建匿名方法。但有时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);

}}

假设你的社交网络应用程序的成员包含在一个数组中,并且你希望按年龄对数组hFjGNbfU进行排序。你可以使用以下代码:

Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);

class PersonAgeCompahFjGNbfUrator implements Comparator {

public int compare(Person a, Person b) {

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

}

}

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

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

注意,接口comparator是一个功能接口。因此,你可以使用lambda表达式,而不是定义并创建实现comparator的类的新实例,所以上上面的代码可以用lambda表达式改写成下面这样:

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

Arrays.sort(rosterAsArray,

(Person a, Person b) -> {

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

}

);

因为这个上面这个lambda表达式是在调用现有的方法,所以我们这里就可以使用上面提到的使用方法引用方式(及双冒号 ::),而不是之前我们熟悉的lambda表达式:

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

方法引用 person::comparebyage 在语义上与lambda表达式(a,b)->person.comparebyage(a,b)相同。他们都有以下特点:

它的形参列表复制自comparator.compare,即(Person, Person)。

它的主体调用方法是:person.comparebyage。

二、方法引用的种类(哪些场景可以使用方法引用)

有四种方法引用:

种类

案例

引用静态方法

ContainingClass::staticMethodName

对特定对象的实例方法的引用

containingObject::instanceMethodName

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

ContainingType::methodName

对构造函数的引用

ClassName::new

1、引用静态方法

例如:

Person::comparebyage 是对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::compareTogignoreCase  的等效lambda表达式会有形参列表(String a,String b),其中a和b是用于更好地描述此示例的任意名称。这次的方法引用,将调用方法a.CompareTognoreCase(b)。

如何理解:对特定类型的 任意对象的 实例方法的引用  这句话呢?

实际上上面代码没有在特定实例(也就是没有new一个指定的String 实例出来,像这样:String s = new String() ,s就是一个指定的String对象的实例)上引用方法 compareTogignoreCase ,而是在String类自身引用的。

以此类推。。。

我可能解释的也不太好,主要就是想语言上理解一下:对特定类型的 任意对象的 实例方法 的引用

4、引用构造函数

你可以通过使用name new 的方式引用构造函数,这与静态方法的引用方式类似。

下面这个示例方法,是将元素从一个集合复制到另一个集合。我们将以这个方法为例,讲解如何使用方法引用的方式引用构造函数。

public static , DEST extends Collection>

DEST transferElements(SOURCE sourceCollection,Supplier collectionFactory) {

DEST result = collectionFactory.get();

for (T t : sourceCollection) {

result.add(t);

}

return result;

}

函数接口supplier包含一个无参但返回一个对象的get方法,源码可见,他返回的类型就是泛型的类型,如下:

因此,可以使用lambda表达式调用方法transferElements,如下所示:

Set rosterSetLambda =

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

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

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

上面代码,Java编译器执行的时候会自动推断出这里想要创建一个包含Person类型元素的hashset集合。当然你也可以显示的指定类型,如下:

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:pagehelper插件显示total为
下一篇:浅谈SpringBoot主流读取配置文件三种方式
相关文章

 发表评论

暂时没有评论,来抢沙发吧~