Java 8 新增的函数式接口是个令人惊喜的特性。Java是一门面对对象的语言,在Java中对象是一等公民,函数无法作为另一个函数的参数。而函数式接口提供了将函数作为参数能力,将函数作为参数参与另一个函数的执行,让函数拥有更强的灵活性。
纯函数
纯函数有两个特性不可变对象和无副作用,不可变对象和无副作用特性保证函数执行结果的稳定
不可变对象:除参数外,函数执行所使用的数据(对象)是固定不变的不可变对象保证了参数不变时,函数执行的结果不变。例如函数y = x + 1,参数x不变时,结果y也不会改变。而如果将常量1换成从数据库查询,即y = x + db(x)那么由于db(x)查询结果的不固定,这个函数y = x + db(x)不具有不可变对象特性无副作用:函数不会修改外部数据或对象无副作用在并发编程时很有用,因为不会修改外部对象,在使用时不用考虑多线程执行顺序不固定时出现意外的结果
函数副作用:指当调用函数时会产生附加的影响。例如修改全局变量或修改参数
Lambda表达式
Lambda表达式的意思是匿名函数,即Lambda表达式产生是函数,而不是类
Lambda的结构为(参数) -> {}, ->表示传递执行, {}表示函数体(函数的执行逻辑),例如:
Function<Integer, Integer> add = (Integer x) -> {
return x + 1;
};
Function<Integer, Integer> add1 = (Integer x) -> x + 1;
- 当只用一个参数,可以不需要括号
()- 如果没有参数,则必须使用括号
()表示空参数列表- 对于多个参数,将参数列表放在括号
()中- 当函数体只有一行时,可以不写return
Lambda很重要的一个作用就是取待匿名对象的实现,例如:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
Thread thread1 = new Thread(() -> System.out.println("hello"));
方法引用
方法引用表示一个函数, 通过类名或实例名::方法名称的方式定义一个函数,例如;
public void test() {
Function<Integer, Integer> add = this::add;
}
private Integer add(int x){
return x + 1;
}
函数式接口
Java 8中满足只包含一个抽象方法的接口称为函数式接口。通常使用@FunctionalInterface 注解显示声明该接口是函数式接口。例如:
@FunctionalInterface
public interface AddFunction<T, R> {
Integer add(T t, R r);
}
在java.util.function包中系统提供了一些基本的函数式接口,如下图:
其中最常用的有
Function<T, R>、Supplier<T>、Consumer<T>、Predicate<T>
Function<T, R>
Function<T, R>: 表示接受一个参数并返回结果的函数。
即接收一个T类型的参数,返回一个R类型的结果,函数定义如下图:
任何符合该形式的函数都可以看作
Function<T, R>的实现类,调用apply方法执行该函数,如下图:
函数式接口中可以存在默认方法和静态方法,Function<T, R>中提供了两个组合方法compose和andThen
compose:先执行参数操作,再执行原操作compose接收接收一个Function<T, R>作为参数,并返回一个组合后的的新函数。该参数(Function)的执行结果作为原函数的参数执行示例:
-
andThen:先执行原操作,再执行参数操作andThen同样接收接收一个Function<T, R>作为参数,返回一个组合后的的新函数。但是不同的是andThen中两个函数是顺序执行的,即执行原函数,并将原函数的执行结果作为参数(Function)的参数示例:
Supplier<T>
Supplier<T>: 表示不需要参数只返回结果的函数。Supplier的意思是生产者/提供者, 常用在提供一些默认值或者已默认的方式提供数据的地方
示例:
Consumer<T>
Consumer<T>: 表示接受单个输入参数且不返回结果的函数。Consumer的意思是消费者,常用在对数据执行操作,并且不需要返回值的地方。Consumer的函数定义如下:
示例:
Consumer<T>中也有一个组合函数andThen,表示按顺序消费参数,函数定义如下图:
示例:
Predicate<T>
Predicate<T>: 表示接收单个参数并返回布尔值的函数。Predicate的意思是断言/谓语,常用来表示一些判断,函数定义如下图:
Predicate<T>中的组合函数有and、or、negate,表示与或非逻辑
示例:
柯里化
将一个多参数的函数,转换为一系列单参数函数称为函数柯里化。具体做法为通过将单个参数都转换成函数,参数之间的最终转换成参数和函数之间的联系,例如:
BiFunction<Integer, Integer, Integer>: 表示两个参数有返回值的函数 上图中add函数有两个参数, 柯里化的方式就是将第二个参数和返回值转换成一个新的函数,并作为第一个参数的返回值