之前我们一提到Java8新特性,两个常提的stream和Lambda表达式,实际还有一个大的方向就是函数接口。但是stream和Lambda表达式,使用场景也比较多,基本一推出来,基本日常场景就能用到。但是函数接口就不一样,他需要他自己的使用场景,如果不理解,只背他的定义,实际没啥帮助。这里我就通过介绍使用场景的方式来说一下Supplier函数接口。
一 使用场景
我们日常会用到泛型,java.util.function.Supplier 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据。
那就只有一个get方法,有什么可以用到的场景,其实就是封装对象,这里我有两个场景可以介绍一下。
第一种,redis保存数据,大家都有共同的属性,过期单位和设置过期时间,但是里面的对象不确定,这里我们可以将对象以泛型的形式,作为suplier构成。
public class RedisSupplier <T> {
private int expire;
private TimeUnit timeUnit;
Supplier<T> supplier;
public int getExpire() {
return expire;
}
public void setExpire(int expire) {
this.expire = expire;
}
public TimeUnit getTimeUnit() {
return timeUnit;
}
public void setTimeUnit(TimeUnit timeUnit) {
this.timeUnit = timeUnit;
}
public Supplier<T> getSupplier() {
return supplier;
}
public void setSupplier(Supplier<T> supplier) {
this.supplier = supplier;
}
public RedisSupplier(int expire, TimeUnit timeUnit, Supplier<T> supplier) {
this.expire = expire;
this.timeUnit = timeUnit;
this.supplier = supplier;
}
public T get() {
return this.supplier.get();
}
}
第二种,就是我们工作流,对应taskid这些都是固定的,对应不同的工作流参数,我们需要一个泛型管理起来。
protected abstract void updateDetail(Supplier<? extends InStorageBaseParam<?>> supplier, Long merchantId, boolean isApproval, InStorageOrderDO inStorageOrderDO, Attribute.ArticleAttribute attribute);
二 如何使用工作流
看Supplier里面只有一个get方法,获取一个泛型对象,那怎么把这个对象塞进去。
借助Lambda
借助lambad表达式直接塞对象进去。
Supplier<String> str = () -> "ZP handsome.";
System.out.println("lambda Supplier :" + str.get() );
我们还可以借助对象里面的方法,进行调用。比如我们定义了一个makerMoney。
package com.example.test.j8.supplier;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/11/12
*/
public class Person {
private Integer age;
private String name;
public Person(){}
public Person(Integer age, String name){
this.age = age;
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String makerMoney(){
return " make money for live. ";
}
}
然后调用(实际::双冒号就是调用方法的意思)
Supplier<String> str1 = person::makerMoney;
System.out.println(" Non static method Supplier :" + str1.get());
构造方法
构造方法是现实中用的最多的一种方式,向Supplier塞进对象。
//真正使用场景,就是传参一个对象进去
PersonSupplier<String> ps1 = new PersonSupplier<>(18,"卖课",()->"嘎嘎噶韭菜" );
System.out.println(" construction method Supplier : " + ps1.getSupplier().get());
PersonSupplier<WebSite> ps2 = new PersonSupplier<>(18,"卖课",()->new WebSite("XX课程","高并发") );
System.out.println(" construction method Supplier : " + ps2.getSupplier().get().getWebSiteName() + ps2.getSupplier().get().getTarget() );
具体代码参见我的GitHub对应目录
以上演示的完整代码
扩展
实际上和Supplier还有一个对应相反的一个函数接口,Consumer,听名字上可以这么区分,Supplier生产者,该接口定义一个无参的get方法,() -> T,如果不接受入参,直接为我们生产一个指定的结果,那么就可以用Supplier。
生产一个指定的结果
Conusmer消费者,该接口定义了一个void accept(T)的抽象方法,其函数描述符为 (T) -> void,如果你需要一个操作某一对象,但无需返回的的函数式接口,那么就可以使用Consumer接口。