Java 8是Java在保持向后兼容的前提下首次迈出重要一步,相比之前,不再是只对类库的改良,在编写复杂的集合处理、并行化执行、代码简洁度等方面都有颠覆性的提升。本文将探索和理解函数式编程的含义,以及它在Java 8中的实现。
一、理解函数式编程
Java倡导“一切皆对象”,面向对象编程(OOP)是对数据进行抽象,主要抽象类/对象,是命令式编程风格。而函数式编程(OOF)是对行为进行抽象,主要是抽象函数,是声明式编程风格,其核心是:在思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值。
二、Java 8 为实现函数式编程提供的支持
1、Lambda表达式
定义:本质上是一段匿名内部类,也可以是一段可以传递的代码(将代码像数据一样进行传递)。
作用:使代码更简洁、更灵活、更紧凑。
语法:()->();
口诀:左右遇一省括号,左侧推断类型省
/** case1-表达式不包含参数 */
Runnable noArguments = () -> System.out.println("Hello Word");
/** case2-表达式只有一个参数 */
Consumer tConsumer = evnet -> System.out.println("Hello Word");
/** case3-表达式的主体是一段代码块 */
Runnable multiStatement = () -> {
System.out.printf("Hello");
System.out.println(" Word");
};
/** case4-表达式有多个参数 */
BinaryOperator<Long> addFun = (x, y) -> x + y;
/** case5-显示声明表达式参数类型,而非编译器推断 */
BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;
2、引用
作用:是Lambda表达式的另外一种表现形式,且语法比Lambda表达式更加简单
类型:
-
方法引用[对象-实例方法、类-静态方法、类-实例方法]:ClassName::monthod
-
构造器引用:ClassName::new
-
数组引用:Type[]::new
/** 方法引用-ClassName::monthod */
Consumer<String> consumer = System.out::println;
// 方法引用-类名::静态方法名
BiFunction<Integer, Integer, Integer> biFunction = Integer::compare;
biFunction.apply(10, 20);
// 方法引用-类名::实例方法名
BiFunction<String, String, Boolean> booleanBiFunction = String::equals;
booleanBiFunction.apply("hello", "hello");
/** 构造器引用:ClassName::new */
Supplier<LambdaDemo> supplier = LambdaDemo::new;
/** 数组引用 Type[]::new */
Function<Integer, String[]> function = String[]::new;
function.apply(10);
3、类型推断
在Lambda 表达式中无需指定类型,程序依然可以编译,由编译器根据程序的上下文推断出来,这就是所谓的“类型推断”。实际上是Java 7中引入的目标类型推断(菱形操作符)的扩展。
4、函数式接口
定义:函数接口是只有一个抽象方法的接口,使用只有一个方法的接口来表示某特定方法并反复使用,是一种表示函数的方式。任何需要函数式接口的地方,我们都可以使用Lambda表达式(或方法引用)。
作用:为了给Lambda表达式的使用提供更好的支持,不需要自己再手动创建一个函数式接口,直接拿来用就好了。
使用:
-
自定义函数式接口:在接口上标注@FunctionalInterface 注解。
-
java.util.function包下定义了Java 8提供的函数式接口,可直接使用。
/**
* 核心函数式接口
*/
// Consumer
Consumer<String> consumer = str -> System.out.println(str);
consumer.accept("Consumer-消费型,有入参无返回");
// Supplier
Supplier<String> supplier = () -> "Supplier-供给型,无入参有返回";
System.out.println(supplier.get());
// Function
Function<Integer, String> function = integer -> {
if (integer > 0) {
return "入参大于0";
}
return "入参小于等于0";
};
System.out.println("Function-函数市接口,有入参有返回" + function.apply(-10));
// Predicate
Predicate<Integer> predicate = integer -> integer < 10;
System.out.println("Predicate-断言型接口,有入参有返回" + predicate.test(20));
/**
* 扩展函数式接口
*/
// BiFunction
BiFunction<Integer, Integer, Integer> biFunction = (x, y) -> x * y;
biFunction.apply(2, 2);
类型 | 函数式接口 | 方法 |
四大核心函数式接口 | Consumer<T> 消费型接口 | void accept<T t> |
Supplier<T> 供给型接口 | T get() | |
Function<T, R> 函数型接口 | R apply(T t) | |
Predicate<T> 断言型接口 | boolean test(T t) | |
Consumer-扩展函数式接口 | DoubleConsumer<T> LongConsumer<T> IntConsumer<T> | void accept(double value) void accept(long value) void accept(int value) |
ObjDoubleConsumer<T> ObjLongConsumer<T> ObjIntConsumer<T> | void accept(T t, double value) void accept(T t, long value) void accept(T t, int value) | |
Supplier-扩展函数式接口 | BooleanSupplier DoubleSupplier LongSupplier IntSupplier | boolean getAsBoolean() double getAsDouble() long getAsLong() int getAsInt() |
Function-扩展函数式接口 | BiFunction<T, U, R> | R apply(T t, U u) |
DoubleFunction<R> LongFunction<R> IntFunction<R> | R apply(double value) R apply(long value) R apply(int value) | |
ToDoubleFunction<T> ToLongFunction<T> ToIntFunction<T> | double applyAsDouble(T value) long applyAsLong(T value) int applyAsInt(T value) | |
ToDoubleBiFunction<T, U> ToLongBiFunction<T, U> ToIntBiFunction<T, U> | double applyAsDouble(T t, U u) long applyAsLong(T t, U u) int applyAsInt(T t, U u) | |
DoubleToIntFunction DoubleToLongFunction | int applyAsInt(double value) long applyAsLong(double value) | |
LongToDoubleFunction LongToIntFunction | double applyAsDouble(long value) int applyAsInt(long value) | |
IntToDoubleFunction IntToLongFunction | double applyAsDouble(int value) long applyAsLong(int value) | |
Predicate-扩展函数式接口 | BiPredicate<T, U> | boolean test(T t, U u) |
DoublePredicate LongPredicate IntPredicate | boolean test(double value) boolean test(long value) boolean test(int value) |
-------------------------------------------------------------------------------------------------------------------------------