两个类使用双冒号连接_函数式编程,方法引用,Java双冒号(::)示例详解

本文详细介绍了Java中的方法引用,包括四种类型:静态方法引用、实例方法引用、任意对象实例方法引用和构造函数引用,并给出了具体示例。同时,结合函数式接口,展示了如何使用方法引用简化代码,例如在排序、构造新集合和调用方法等方面的应用。此外,还探讨了方法引用在Elasticsearch等场景中的实际应用。
摘要由CSDN通过智能技术生成

第一部分

方法引用,又称双冒号(::),是简化的lambda表达式,主要使用形式包括四种:

方法引用的形式(Kinds of Method References)

类型

Kind

Example

指向静态方法的引用

Reference to a static method

ContainingClass::staticMethodName

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

Reference to an instance method of a particular object

containingObject::instanceMethodName

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

Reference to an instance method of an arbitrary object of a particular type

ContainingType::methodName

指向构造函数的引用

Reference to a constructor

ClassName::new

考虑以下例子:

Person类

1 importjava.time.LocalDate;2

3 public classPerson {4

5 public enumSex {6 MALE, FEMALE7 }8

9 String name;10 LocalDate birthday;11 Sex gender;12 String emailAddress;13

14 publicPerson(String name, LocalDate birthday, Sex gender) {15 this.name =name;16 this.birthday =birthday;17 this.gender =gender;18 }19

20 public intgetAge() {21 int age =LocalDate.now().minusYears(birthday.getYear()).minusDays(birthday.getDayOfYear()).getYear();22 returnage;23 }24

25 publicLocalDate getBirthday() {26 returnbirthday;27 }28

29 public static intcompareByAge(Person a, Person b) {30 returna.birthday.compareTo(b.birthday);31 }32 }

如果对Person数组排序,可通过下面这种方式,先声明一个类,然后实例化。

①实例化类的写法:

1 List roster =Arrays.asList();2

3 Person[] rosterAsArray = roster.toArray(newPerson[roster.size()]);4

5 class PersonAgeComparator implements Comparator{6 public intcompare(Person a, Person b) {7 returna.getBirthday().compareTo(b.getBirthday());8 }9 }10

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

静态方法sort的方法签名:

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

Comparator是一个函数式接口

1 @FunctionalInterface2 public interface Comparator{3

4 intcompare(T o1, T o2);5 }

②可以通过lambda表达式,替换创建一个类:

返回值为compare的方法体

1 Arrays.sort(rosterAsArray,2 (Person a, Person b) ->{3 returna.getBirthday().compareTo(b.getBirthday());4 }5 );

③单独的表达式,可以去掉return和大括号,写法为:

1 Arrays.sort(rosterAsArray, (Person a, Person b) -> a.getBirthday().compareTo(b.getBirthday()));

④参数类型可以自动推断,可以去掉参数类型:

1 Arrays.sort(rosterAsArray, (a, b) -> a.getBirthday().compareTo(b.getBirthday()));

⑤方法引用可以使代码进一步简洁:

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

下面示例演示4种类型

1)指向静态方法的引用

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

2)指向类实例方法的引用

1 String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda"};

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

3)指向特定类型任意对象实例方法的引用

1 classComparisonProvider {2 public intcompareByName(Person a, Person b) {3 returna.getName().compareTo(b.getName());4 }5

6 public intcompareByAge(Person a, Person b) {7 returna.getBirthday().compareTo(b.getBirthday());8 }9 }10 ComparisonProvider myComparisonProvider = newComparisonProvider();11 Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);

4)指向构造函数的引用

有如下方法,将一个集合转为另外一个集合

1 public static , DEST extends Collection>

2 DEST transferElements(3 SOURCE sourceCollection,4 SuppliercollectionFactory) {5

6 DEST result =collectionFactory.get();7 for(T t : sourceCollection) {8 result.add(t);9 }10 returnresult;11 }

转换如下:

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

简洁写法如下:

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

上述代码隐藏了泛型:

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

- - - - - - - - - - - - - - - - - - - - 分割线 - - - - - - - - - - - - - - - - - - - -

第二部分

下面结合方法引用对应的(内置)函数式接口,通过代码示例,详细解说。

双冒号(::)和 箭头函数(->)一并展示如下:

如:HashMap::new  等同于  ( ) -> new HashMap()

熟悉方法引用对应的函数式接口很重要,因为它是方法的参数。熟悉了它,可以结合Java高级特性(泛型、反射等)写出抽象可复用的函数式代码。

1 importjava.util.ArrayList;2 importjava.util.Arrays;3 importjava.util.LinkedList;4 importjava.util.List;5 importjava.util.function.BiConsumer;6 importjava.util.function.BiFunction;7 importjava.util.function.Consumer;8 importjava.util.function.Function;9 importjava.util.function.Supplier;10 importjava.util.stream.Collectors;11

12 public classTest {13

14 //实例对象引用实例方法

15 Supplier supplier1 = "lowerCase"::toUpperCase;16 Supplier supplier1_1 = () -> "lowerCase".toUpperCase();17

18 //类引用(无参)构造函数

19 Supplier supplier2 = String::new;20 Supplier supplier2_1 = () -> newString();21

22 //类引用(有参)构造函数

23 Function function1 = String::new;24 Function function1_1 = (String str) -> newString(str);25

26 //类引用实例方法,入参为传入实例对象,入参、出参同类型

27 Function function2 =String::toUpperCase;28 Function function2_1 = (String str) ->str.toUpperCase();29

30 //Predicate可理解为特殊的Function

31

32 Person person = newPerson();33 //须为无参静态方法

34 Supplier supplierBln =Person::isTest;35 Supplier supplierBln_1 = () ->Person.isTest();36

37 //实例对象调用实例方法

38 Supplier supplierStr =person::getName;39 Supplier supplierStr_1 = () ->person.getName();40

41 //无参构造函数

42 Supplier supplierPerson = Person::new;43 Supplier supplierPerson_1 = () -> newPerson();44

45 //有参构造函数

46 BiFunction biFunction = Person::new;47 BiFunction biFunction_1 = (name, gender) -> newPerson(name, gender);48

49 //类名调用set方法,特定场景下,可取代反射

50 BiConsumer biConsumer =Person::setName;51

52 //类名调用实例方法,入参为传入实例对象

53 Function functionP =Person::toOpposite;54 Function functionP_1 = person ->person.toOpposite();55

56 Consumer consumer =System.out::println;57 Consumer consumer_1 = (String str) ->System.out.println(str);;58

59 public static voidmain(String[] args) {60 List list = Arrays.asList("1", "2", "3");61 boolean bl = list.stream().anyMatch("1"::equals);62 List retval = list.stream().collect(Collectors.toCollection(LinkedList::new));63

64 List persons = Arrays.asList(new Person(10, "Jack", "M"));65 Person person = new Person(20, "Lily", "F");66 persons.stream().filter(Person::isMale).filter(person::isUnder).collect(Collectors.toCollection(ArrayList::new));67 }68 }

Person类代码如下:

1 public classPerson {2 intage;3 String name;4 String gender;5

6 publicPerson() {7 }8

9 publicPerson(String name) {10 this.name =name;11 }12

13 publicPerson(String name, String gender) {14 this.name =name;15 this.gender =gender;16 }17

18 public Person(intage, String name, String gender) {19 this.age =age;20 this.name =name;21 this.gender =gender;22 }23

24 publicString getName() {25 returnname;26 }27

28 public voidsetName(String name) {29 this.name =name;30 }31

32 publicPerson toOpposite() {33 if (gender.charAt(0) == 'M')34 gender = "F";35 else

36 gender = "M";37 return this;38 }39

40 public static booleanisTest() {41 return true;42 }43

44 public booleanisUnder(Person person) {45 return person.age > this.age;46 }47

48 public booleanisMale() {49 return gender.equals("M");50 }51 }

- - - - - - - - - - - - - - - - - - - - 分割线 - - - - - - - - - - - - - - - - - - - -

第三部分

扩展至自定义的函数式接口

下面结合Elasticsearch,进一步实例讲解

指向类静态方法的引用

NodesUsageResponse节点使用响应,50行使用了方法引用

59b3b66f1c826df7b08cd6a4585d7a55.png

泛型方法,入参为函数Reader

27051bb02d4c6e855794211fc9b66da5.png

函数式接口Reader,定义了方法reader(StreamInput in):

80182a5cd7fab0675c1a7c620bc72c42.png

reader.read(this)实际调用函数是

8cbf64fa533b5a16b4ff32da9393a4bb.png

第三种类型

指向特定类型任意对象实例方法的引用(Reference to an Instance Method of an Arbitrary Object of a Particular Type)

TransportService传输服务,构造函数164行使用了方法引用

0ed1e09f95e180b12f9958daf626f76a.png

成员变量asyncSender和interceptor

45e17131f3633e90b227a01a416e9656.png

作用为请求发送拦截器接口TrsnsportInterceptor,调用的为49行,返回AsyncSender函数式接口,57行为函数式接口定义。

0b9a5879cb9af17e2d9544737c6c78dd.png

TransportService构造函数,使用了类实例方法sendRequestInternal

518f8b84734e7fc804f912944b6eb83e.png

sendRequestInternal(Connection connection, String action, TransportRequest request, TransportRequestOptions options, TransportResponseHandler handler)

方法sendRequestInternal的方法参数列表、返回值类型和接口TransportInterceptor中的函数是接口AsyncSender一致。

第四种类型

指向构造函数的应用

构造函数,以67行为例

afcab3dead42e86cb7c9c4ea16680769.png

泛型方法 StreamInput # readOptionalWriteable

a0936decc608f9a1fa24b3810a8f6534.png

方法引用DiscoveryNode::new,实际调用构造函数如下

e89f3496793bdc3b88f33deb527a25a2.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值