函数式编程概述
为了实现类似JavaScript等动态语言中callback函数的灵活语法,Java 8开始支持Lambda(λ)表达式和函数式编程语法。
什么是Lambda表达式(λ)?
Lambda其实是是希腊字母λ的英文发音。在Java中,Lambda表达式的组成三要素:
- ():里面没有内容,可以看成是方法形式参数为空
- ->:箭头分隔符,指向后面要做的事情
- {}:包含一段代码,我们称之为代码块,可以看成是方法体中的内容
标准格式为:
(形式参数) -> {代码块}
当表达式中的参数只有一个、代码块中只有一行时,以上格式可以简化,参数的()和代码块的{}都可以省略,如下forEach()中的片段:
userList.forEach(u -> System.out.println(u))
什么是函数式接口?
在java.util.function包中,提供了大量以@FunctionalInterface注解修饰的接口,用来代表不同类型的Lambda表达式,分别是:
- Consumer 系列:代表需要参数、但不返回结果的操作
- Consumer<T>:接收一个T类型参数
- BiConsumer<T,U>:接收一个T类型、一个U类型的参数
- IntConsumer:接收一个int类型参数
- ObjDoubleConsumer:接收一个Object、一个double类型参数
- …等等
- Supplier 系列:代表返回结果的操作
- Supplier<T>:返回一个T类型结果
- LongSupplier:返回一个long类型结果
- BooleanSupplier:返回一个boolean类型结果
- …等等
- Predicate 系列:代表返回boolean类型结果的断言操作
- Predicate<T>:基于一个参数返回boolean结果
- IntPredicate:基于int值返回boolean结果
- DoublePredicate:基于double值返回boolean结果
- …等等
- Function 系列:代表有参数、有返回值的函数
- Function<T,R>:接收T类型参数、返回R类型结果的函数
- IntFunction<R>:接收int类型参数,返回R类型结果的函数
- BiFunction<T,U,R>:接收T、U两个参数,返回R类型结果的函数
- …等等
- Operator 系列:代表运算操作
- BinaryOperator<T>:代表两个T类型操作数的运算,产生同类型的结果
- DoubleBinaryOperator:代表两个double值的运算,返回double结果
- DoubleUnaryOperator:基于单个double值进行运算,返回double结果
- …等等
在具体编程中,把以上函数式接口作为方法的形参,那么在调用时就需要传入一个Lambda表达式,实现了一种在Java中 “把代码片段(函数)当做参数进行传递” 的神奇效果。比如,前面提到的代码:
userList.forEach(u -> System.out.println(u));
其实来自于ArrayList的forEach()方法,这个方法在ArrayList类中的声明为:
void forEach(Consumer<? super T> action)
其中的 u -> System.out.println(u) 是一个Lambda表达式,会被编译器解析为Consumer。<? super T>是泛型下界通配符,代表可以接受User及其父类类型。