1. 概述
1.1背景
在日常Java编码中,函数式编程使用的频率是非常高的,但是回想一下,自己虽然能很好的使用,但是却没能系统的了解过函数式编程,所以以下为最近学习的一个总结。
1.2 概念
函数式接口在Java中是指:有且仅有一个抽象方法的接口函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
2. 函数式接口介绍&基本使用
2.1 格式
1
2
3
4
5
6
7
8
9
修饰符 interface 接口名称 {
public abstract 返回值 方法名称(参数列表)
// 其他方式
}
// public abstract 可以不写 编译器自动加上
修饰符 interface 接口名称 {
返回值 方法名称(参数列表)
// 其他方式
}
以最常用的Function为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
2.2 @FunctionalInterface注解
1
2
3
4
5
6
// 标明为函数式接口
@FunctionalInterface
public interface MyFunction {
// 抽象方法
void method();
}
一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。(该接口是一个标记接口)
2.3 自定义函数式接口使用
1
2
3
4
5
6
7
public static void executeMyFunction(MyFunction function) {
function.method();
}
public static void main(String[] args) {
executeMyFunction(()-> System.out.println("Hello World"));
}
2.4 Java自带函数式接口
常用函数式接口
- Supplier 你要作为一个供应者,自己生产数据
- Consumer 你要作为一个消费者,利用已经准备数据
- Function 输入一个或者两个不同或者相同的值转为另一个值
- Predicate 输入一个或者两个不同或者相同的值总是输出boolean
- UnaryOperator 输入一个值转换为相同值输出
- BinaryOperator 输入两个相同类型的值 转为相同类型的值输出
2.4 主要语法
- () -> 代表了 lambda的一个表达式
- 单行代码无需写return (无论函数式接口有没有返回值),花括号
- 多行代码必须写花括号,有返回值的一定要写返回值
- 单行代码且有参数的情况下可以不写 () 如 s->System.out.println(s)
- (T t)中的参数类型可写可不写
3. 常用函数式接口
3.1 Supplier接口(供应接口)
- 接口名:java.util.function.Supplier
- 抽象方法:接口仅包含一个无参的方法: T get()
- 作用:用来获取一个泛型参数指定类型的对象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
- 使用
1 2 3 4 5 6 7
private static String supplierFunction(Supplier<String> stringSupplier){ return stringSupplier.get(); } public static void main(String[] args) { System.out.println(supplierFunction(()->"Hello World")); }
3.2 Consumer接口
- 接口名:java.util.function.Consumer
- 抽象方法:void accept(T t)
作用:接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定
- 默认方法:andThen
- 作用:如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作,然后再做一个操作,实现组合
1 2 3 4 5 6 7
default Consumer<T> andThen(Consumer<? super T> after) { //1: 返回值为Consumer 那么需要 ()-> 表示函数式接口 //2: accept(t);为生产一个数据供应给 (T t)中的t //3: after.accept(t);为利用这个t再次生成新的函数式接口 实现类始于builder的设计模式 Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }
3.3 Predicate接口
- 接口名:java.util.function.Predicate
- 抽象方法:_boolean _test(T t)
作用:需要对某种类型的数据进行判断,从而得到一个boolean值结果
- 默认方法:
- Predicate
and(Predicate<? _super _T> other) - _default _Predicate
or(Predicate<? _super _T> other) - _default _Predicate
negate() (取反)
- Predicate
作用:既然是条件判断,就会存在与、或、非三种常见的逻辑关系。
- 静态方法:_static _
Predicate isEqual(Object targetRef) - 作用:返回值为Predicate
,返回一个是否与targetRef相等的函数表达式
3.4 Function接口
- 接口名:java.util.function.Function<T, R>
- 抽象方法:R apply(T t)
作用:根据一个类型的数据得到另一个类型的数据
- 默认方法:
- _default _
Function<V, R> compose(Function<? _super _V, ? _extends _T> before) - _default _
Function<T, V> andThen(Function<? _super _R, ? _extends _V> after)
- _default _
- 作用:与另一个Function进行结合,一个方法为before,另一个为after
1 2 3 4 5 6 7 8
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }