如何建设网站挣钱微信推广平台
解决的问题:Java中实现函数传递。
在Java编程的实践过程中,有一些场景,我们希望能够将函数传递进去,不同的函数实现代表着不同的策略,这在JDK8以前,需要定义一个接口,这个接口中定义这个函数方法,然后传递这个接口的不同实现类进去,从而实现不同的策略,在JDK8及以后,可以使用lambda表达式做简化。
JDK8以前,我们想实现一个从不同数据库获取数据的策略,如下所示:
/*** 定义接口,从某一数据源获取数据*/
public interface GetStrategy(){Bean get();}
/*** 实现类:Mysql。*/
public class MysqlGetStrategy(){private MysqlDao mysqlDao;Bean get(){return mysqlDao.get();}
}
/*** 实现类:Squirrel*/
public class RedisGetStrategy(){private RedisDao redisDao;Bean get(){return redisDao.get();}
}/*** 获取数据后再处理数据*/
public class Processor(){private GetStrategy getStrategy;public Processor(GetStrategy getStrategy){this.getStrategy = getStrategy;}private void process(){Bean bean = getStrategy.get();// process bean}
}public static void main(String[] args){GetStrategy getStrategy = new MysqlGetStrategy();Processor processor = new Processor(getStrategy);processor.process();
}
可以看到上述代码比较繁复,为了实现将函数(即get方法)传递给Processor,我们需要
- 定义一个接口GetStrategy
- 定义一个实现类
当然,我们可以使用匿名内部类的方式简化上述的代码,如下所示:
/*** 定义接口,从某一数据源获取数据*/
public interface GetStrategy(){Bean get();}/*** 获取数据后再处理数据*/
public class Processor(){private GetStrategy getStrategy;public Processor(GetStrategy getStrategy){this.getStrategy = getStrategy;}private void process(){Bean bean = getStrategy.get();// process bean}
}public static void main(String[] args){Processor processor = new Processor(new GetStrategy(){public Bean get(){return MysqlDao.get();}});processor.process();
}
但以上代码仍然比较复杂,复杂在
- 仍然需要定义一个接口GetStrategy。
- 在创建匿名内部类时,仍然较复杂,需要把方法名重新写一遍。
在JDK1.8后,提供了Lambda表达式,解决了函数传递的问题,不需要我们再做繁复的接口定义和实现类定义了,如下
private class Processor{/*** JDK 自定义函数,无参,有返回值。*/private Supplier<Bean> supplier;public Processor(Supplier<Bean> supplier){this.supplier = supplier;}public void process(){Bean bean = supply.supply();// process逻辑}
}public static void main(String[] args){Supply<Bean> supply = MysqlDao::get;Processor processor = new Processor(supply);processor.process();
}
从上述代码可以看到,此语法糖实现方式为
- 在java.util.function包中,定义了很多不同类别的接口(例如上述的Supplier接口),用以替代自己定义的接口(例如第一,二个代码片段中的GetStrategy)
- 使用lamdba表达式对匿名类的创建进行简化(例如MysqlDao::get)。
替代代码如下:
/*** JDK8以下:定义接口,从某一数据源获取数据*/
public interface GetStrategy(){Bean get();
}/*** JDK8替代:JDK自带Supplier接口*/
Supplier<Bean> supplier/*** JDK8以下匿名内部类*/
new GetStrategy(){public Bean get(){return MysqlDao.get();}});/*** JDK8替代:lambda匿名内部类表达方式*/
MysqlDao::get
关于JDK8中java.util.function中的自定义接口
在java.util.function包中,有很多不同的接口用于替代一些简单的接口的定义,有Consumer,Supplier,Function,BiFunction等,分别对应了不同的函数实现,能够囊括大多数的函数的定义。
Consumer定义了一个参数,无返回值的函数。
BiConsumer定义了两个参数,无返回值的函数。
Supplier定义了一个有返回值,无参数的函数。
Function定义了一个有返回值,有参数的函数。
BiFunction定义了一个有返回值,有两个参数的函数。
但在一些函数参数超多的场景,例如三个参数,四个参数,java.util.function包中并未有相应的实现,如果我们需要的是有返回值的参数,这时可以引入如下jar包。
<dependency><groupId>io.vavr</groupId><artifactId>vavr</artifactId><version>0.9.0</version>
</dependency>
其可以支持参数最多到8个的Function接口,至于8个以上,可能我们要重新审视一下此函数是否可以被重构以降低参数数量。