Java8的新特性,函数式编程和流式操作与Scala很相似。
函数式编程
OO(object oriented)是抽象数据,FP(functional programming)是抽象行为,函数式编程具有以下特点:
- 代码创建复用:通过合并现有代码来生成新功能而不是从头开始编写所有内容
- 并行编程,可靠性:不可变的变量,将值传递给函数,该函数然后生成新值但不修改自身外部的任何东西(包括其参数或该函数范围之外的元素)
语法糖
- lambda表达式:匿名函数,可以替代匿名内部类
(params) -> {function body}
- 可指定参数类型:
(type param) -> {function body}
- 方法引用:
object::method
,Class::method
函数接口
java.util.function
包下提供了默认的函数接口@FunctionalInterface
标记接口,编译器会检测该接口是否只有一个函数式方法(抽象方法),作为Lambda 表达式和方法引用的目标类型
常见接口
Predicate
– 传入一个参数,返回一个bool结果。函数式方法为boolean test(T t);
Consumer
– 传入一个参数,无返回值。 函数式方法为void accept(T t);
Function
– 传入一个参数,返回一个结果。函数式方法为void accept(T t);
BiFunction
– 传入两个参数,类型不同。函数式方法为R apply(T t, U u);
Supplier
– 无参数传入,返回一个结果。函数式方法为T get();
UnaryOperator
– 一元操作符,继承Function
,传入参数的类型和返回类型相同。函数式方法为T apply(T t);
BinaryOperator
– 二元操作符,继承BiFunction
,传入的两个参数的类型和返回类型相同。函数式方法为T apply(T t, T u);
闭包
当函数使用了作用域之外的变量时,由函数及其相关的引用环境组合而成的实体就是闭包
- lambda表达式中引用了局部变量时,局部变量具有
final
或者等同final
效果 - lambda表达式中引用了对象的属性时,属性拥有独立生命周期,所以不需要强制
final
修饰
public class Main {
int field;
// IntSupplier makeFun(final int x) {
IntSupplier makeFun(int x) {
// final int variable = 0;
int variable = 0;
// compile error
// return () -> x++ + variable++;
return () -> x + field++;
}
}
高阶函数
用于消费或者产生函数的函数
常见的组合函数就是高阶函数
andThen(argument)
:先执行调用者,再执行参数compose(argument)
:先执行参数,再执行调用者and(argument)
or(argument)
negate()
柯里化
将一个多参数的函数,转换为一系列单参数函数
// 柯里化函数
Function<String, Function<String, String>> sum =
a -> b -> a + b;
// 部分应用
Function<String, String> a = sum.apply("a")
// res: a1
a.apply("1")
// res: a2
a.apply("2")
流式编程
流是一系列与特定存储机制无关的元素。流可以使程序短小精悍,当应用 Lamda 表达式和方法引用时,更加地优雅。当使用parallel()
时,可以将流分割为多个,并在不同处理器上分别执行操作,提升效率。
流创建
// 创建对象流,流中的元素都是对象
Stream.of(1, 2, 3);
Arrays.asList(1, 2, 3).stream();
// 创建数字流,流中的元素都是基本类型
IntStream.rangeClosed(1, 3);
IntStream.of(1, 2, 3);
IntStream ints = new Random().ints();
// 将数字流包装成对象流
ints.boxed();
// builder
IntStream.builder().add(1).add(2).build();
// iterate
Stream.iterate(1, i -> i + 1); // 1, f(1), f(f(1)), ...
// generate
Stream.generate(() -> 1); // 1, 1, 1, ...
中间操作
Peek
:消费元素,但不改变流,适用于调试sorted(Comparator)
:排序distinct
:去重filter(Predicate)
:过滤map(Function)
,mapToInt(Function)
,…:应用函数到元素flatMap(Function)
,flatMapToInt(Function)
,…:组合流skip(n)
:跳过limit(n)
:截断
终端操作
- 数组
toArray
toArray(generate)
- 循环
forEach(Consumer)
forEachOrdered(Consumer)
:按原始流顺序迭代
- 集合
collect(Collector)
:由收集器收集流元素至集合中collect(Supplier, BiConsumer, Biconsumer)
:第一个参数 Supplier 创建了一个新结果集合,第二个参数 BiConsumer 将下一个元素包含到结果中,第三个参数 BiConsumer 用于将两个值组合起来
- 组合
reduce(BinaryOperator)
reduce(T, BinaryOperator)
:T`为初始值
- 匹配
allMatch(Predicate)
:如果流的每个元素根据提供的Predicate
都返回 true 时,结果返回为 true。在第一个 false 时,则停止执行计算。anyMatch(Predicate)
:如果流中的任意一个元素根据提供的Predicate
返回 true 时,结果返回为 true。在第一个 false 是停止执行计算noneMatch(Predicate)
:如果流的每个元素根据提供的Predicate
都返回 false 时,结果返回为 true。在第一个 true 时停止执行计算
- 查找
findFirst()
:返回第一个流元素的 Optional,如果流为空返回 Optional.emptyfindAny(
:返回含有任意流元素的 Optional,如果流为空返回 Optional.empty
- 信息
- 对象流
count()
max(Comparator)
min(Comparator)
- 数字流
average()
max()
min()
sum()
- 对象流
REFERENCE
[1] On Java8
文档信息
- 本文作者:wzx
- 本文链接:https://masterwangzx.com/2020/07/13/java8-FP/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)