supplier java8_关于JAVA8中关于Supplier的个人理解

本文详细介绍了Java 8中的Supplier接口,它是一个函数式接口,常与lambda表达式结合使用。Supplier接口只有一个无参的get()方法,用于获取泛型T的结果。通过Person::new的示例展示了如何使用Supplier创建对象。文章还探讨了Supplier在Stream API中的应用,如在Collectors.toMap方法中配合使用,将列表转换为Map。总结指出,Supplier接口在Java 8新特性的运用中扮演重要角色,尤其在lambda表达式、Function和Stream操作中。

什么是Supplier

supplier接口是JAVA8以后配合lambda表达式和函数式接口编程(FunctionInterface,以下简称FI)组合使用的一个接口,对外表现为双冒号"::",顺便说下"->"符号对应的是Function接口中的Reply方法例如:Supplier persionSupplier = Person::new;

Arrays.asList("a","b","c").forEach(e->System.out.println(e));

其中的双冒号点击进去就是这个Supplier接口:package java.util.function;

/**

* Represents a supplier of results.

*

*

There is no requirement that a new or distinct result be returned each

* time the supplier is invoked.

*

*

This is a functional interface

* whose functional method is {@link #get()}.

*

* @param the type of results supplied by this supplier

*

* @since 1.8

*/

@FunctionalInterface

public interface Supplier {

/**

* Gets a result.

*

* @return a result

*/

T get();

}

可以看到这份代码中,有一个比较奇特的注解@FunctionalInterface,这是一个函数式接口的声明。该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。

Supplier的使用

我们可以从源代码中看出来,Supplier接口中只有一个方法,就是一个get方法且无需参数,返回的是泛型T。一般的类强制转换为一个接口编译器(eclipse)不会报错但是运行时会报错。假设现在我们新建一个普通类Person:public class Person{

Integer id;

String name;

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Person() {

this.name="mike";

System.out.println("创建了一个对象");

}

public Person(Integer x,String y) {

// TODO Auto-generated constructor stub

this.id = x;

this.name=y;

}

// public String toString() {

// return this.name;

// }

}

Person类中只有基本的属性与get/set方法,最最常见的对象创建方法就是直接一个new,这是正确的我们也恰好使用的是这个特性Person::new

在编译器中这句代码相当于声明一个Person类型的Supplier,返回一个Supplier接口,接下来是重点:使用get方法会执行Person类的无参构造方法,每一次使用get方法都会新建一个对象,所以不是Supplier保存了Person对象,而是需要使用时创建一个,在main中运行以下代码:Supplier persionSupplier = Person::new;

System.out.println("-------------分割线-------------");

System.out.println("supplier中的实体类地址为:"+persionSupplier.get().toString());

persionSupplier.get().setName("coda");

System.out.println("更改后supplier中的实体类地址为:"+persionSupplier.get().toString());

而输出的结果为:

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

创建了一个对象

supplier中的实体类地址为:Person@87aac27

创建了一个对象

创建了一个对象

更改后supplier中的实体类地址为:Person@3e3abc88

可以得知:

第一句代码并没有调用构造方法

第三句代码调用了构造方法所以给出了地址 87aac27

第四句代码也调用了构造方法所以他其实已经不是上面的那个地址为87aac27的Person对象而是一个新的对象了

第五句代码也调用了构造方法所以他是一个全新的对象,地址为:3e3abc88

lambda表达式与Supplier的组合使用

看了以上的同学可能会问,至于吗,我只是想新建一个对象而已,我一个new就能解决的事需要搞这么多花里花俏的?

冷静老哥。JAVA8说了是扩展对象的用法,而不是替代传统的new方式,以下贴代码,注释不需要管,但是也是个学习的东西所以顺便贴上去了,可以解除注释试一下输出:List list = new ArrayList();

list.add(new Person(1, "haha"));

list.add(new Person(2, "rere"));

list.add(new Person(3, "fefe"));

//Map mapp = list.stream().collect(Collectors.toMap(Person::getId, Function.identity()));

//Map mapp = list.stream().collect(Collectors.toMap(x -> x.getId(), x->x));

//System.out.println(mapp);

Map map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName));

//Map map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName,(x1,x2)->x1));

以下的功能很简单,把list中的三个Person对象变成一个Map。Map是一个K-V形式的集合,他要求key不可以重复,所以当我们把Person中的构造方法的123改成相同的那就会出现报错,注意下面那句注释(x1,x2)->x1意味着当第一个和第二个参数的key一致时选用第一个元素,这样即算有两个相同的KEY也不会影响到代码的运行,->是什么我会在另外一篇博文中详细介绍,现在我们只关心::,也就是Supplier在这段代码中起什么作用。Person::getId, Person::getName这句话到底是什么意思,这个我们直接看map的输出就好:

{1=haha, 2=rere, 3=fefe}

看到这个结果我们就知道了Person::getId指的是使用Person对象中的ID作为键,使用Person::getName作为Map中元素的值,getId,getName指的是list中的元素使用的方法名字。虽然可能这段代码还是太过于复杂但是这是我觉得比较适合用来诠释JAVA8的操作拓展改变的所以想了一下还是用的这个例子。

总结

Supplier单独的使用并没有什么意义,但是如果要使用JAVA8的其他新特性例如lambda表达式,Function,stream,Collectors等则需要花点时间看一下,否则会发现同样是JAVA为啥他写的像外星文,我写的像是幼儿园的这种闹剧。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值