Java之函数式接口
函数式接口
只包含一个抽象方法的接口,称为函数式接口。
你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。
我们可以在一个接口上使用 @FunctionalInterface
注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
在java.util.function
包下定义了Java 8 的丰富的函数式接口
我们查看Comparator
接口源码。发现了一些矛盾的地方。
我们发现了该接口中不止包含了一个方法,还存在大量的default
和static
方法。这和上文的定义是矛盾的!!
在jdk8之前,interface之中可以定义变量和方法,变量必须是public、static、final的,方法必须是public、abstract的。由于这些修饰符都是默认的,JDK8及以后,允许我们在接口中定义static方法和default方法。
JDK8接口中的静态方法和默认方法,都不算是抽象方法。。接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
所以该接口的确是一个函数式接口!!
Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP) 编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不 得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还 可以支持OOF(面向函数编程)
在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的 编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在 Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的 对象类型——函数式接口。
简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是 Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口 的实例,那么该对象就可以用Lambda表达式来表示。
所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
@FunctionalInterface
该注解只能标记在”有且仅有一个抽象方法”的接口上。
JDK8接口中的静态方法和默认方法,都不算是抽象方法。
接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
该注解不是必须的,如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
自定义函数式接口
通过对函数式接口概念的认知,我们现在来自定义一个MyFunctionInterface
函数式接口测试。
只包含一个抽象方法
1 | //自定义函数式接口 |
测试类TestFunction
1 | public class TestFunction { |
包含一个覆盖Object方法
覆盖Object的 hashCode
方法
再次运行测试类,成功!说明它是一个函数式接口
1 | //自定义函数式接口 |
包含一个default方法
1 | //自定义函数式接口 |
再次运行测试类,成功!说明它default不是抽象方法,该接口是一个函数式接口
包含一个static方法
1 | public interface MyFunctionInterface<T> { |
再次运行测试类,成功!说明它static不是抽象方法,该接口是一个函数式接口
标注@FunctionInterface注解
通过前面的测试,我们可以明确知道,只要该接口只含有一个抽象方法,它就是一个函数式接口。而不是一定要标注@FunctionInterface注解,这两者之间没有绝对的联系。
该注解不是必须的,如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
1 | //自定义函数式接口 |
四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer<T> 消费型 |
T | void | 对类型为T的对象应用操作,包含方法:void accept(T t) |
Supplier<T> 供给型 |
无 | T | 对类型为T的对象,包含方法:T get() |
Function<T,R> 函数型 |
T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
Predicate<T> 断定型 |
T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法boolean test(T t) |
Consumer消费型
1 |
|
Supplier供给型
1 |
|
Function函数型接口
1 |
|
Predicate断定型接口
1 |
|
其他接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction<T, U, R> | T, U | R | 对类型为 T, U 参数应用操作,返回 R 类型的结 果。包含方法为: R apply(T t, U u); |
UnaryOperator |
T | T | 对类型为T的对象进行一元运算,并返回T类型的 结果。包含方法为:T apply(T t); |
BinaryOperator |
T, T | T | 对类型为T的对象进行二元运算,并返回T类型的 结果。包含方法为: T apply(T t1, T t2); |
BiConsumer<T, U> | T, U | void | 对类型为T, U 参数应用操作。 包含方法为: void accept(T t, U u) |
BiPredicate<T,U> | T,U | boolean | 包含方法为: boolean test(T t,U u) |
ToIntFunction< T > ToLongFunction< T > ToDoubleFunction< T > | T | int long double | 分别计算int、long、double值的函数 |
IntFunction< R > LongFunction< R > DoubleFunction< R > | int long double | R | 参数分别为int、long、double 类型的函数 |