茴子的写法:关于JAVA中的函数传递语法糖:lambda

解决的问题: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,我们需要

  1. 定义一个接口GetStrategy
  2. 定义一个实现类

当然,我们可以使用匿名内部类的方式简化上述的代码,如下所示:

/**
 * 定义接口,从某一数据源获取数据
 */
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();
}

但以上代码仍然比较复杂,复杂在

  1. 仍然需要定义一个接口GetStrategy。
  2. 在创建匿名内部类时,仍然较复杂,需要把方法名重新写一遍。

在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();
}

从上述代码可以看到,此语法糖实现方式为

  1. 在java.util.function包中,定义了很多不同类别的接口(例如上述的Supplier接口),用以替代自己定义的接口(例如第一,二个代码片段中的GetStrategy)
  2. 使用lamdba表达式对匿名类的创建进行简化(例如MysqlDao::get)。

替代代码如下:

/**
 * 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个以上,可能我们要重新审视一下此函数是否可以被重构以降低参数数量。

你可能感兴趣的:(java,开发语言)