解决的问题: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,我们需要
当然,我们可以使用匿名内部类的方式简化上述的代码,如下所示:
/**
* 定义接口,从某一数据源获取数据
*/
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();
}
但以上代码仍然比较复杂,复杂在
在JDK1.8后,提供了Lambda表达式,解决了函数传递的问题,不需要我们再做繁复的接口定义和实现类定义了,如下
private class Processor{
/**
* JDK 自定义函数,无参,有返回值。
*/
private Supplier supplier;
public Processor(Supplier supplier){
this.supplier = supplier;
}
public void process(){
Bean bean = supply.supply();
// process逻辑
}
}
public static void main(String[] args){
Supply supply = MysqlDao::get;
Processor processor = new Processor(supply);
processor.process();
}
从上述代码可以看到,此语法糖实现方式为
替代代码如下:
/**
* JDK8以下:定义接口,从某一数据源获取数据
*/
public interface GetStrategy(){
Bean get();
}
/**
* JDK8替代:JDK自带Supplier接口
*/
Supplier 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包。
io.vavr
vavr
0.9.0
其可以支持参数最多到8个的Function接口,至于8个以上,可能我们要重新审视一下此函数是否可以被重构以降低参数数量。