如果你的好奇心使你翻看 Runnable
接口源代码,你会发现该接口被一个 @FunctionalInterface
的注解修饰,这是 Java 8 中添加的新注解,用于表示 「 函数式接口 」 。
在 Java 8 中,把那些仅有一个抽象方法的接口称为函数式接口。如果一个接口被 @FunctionalInterface
注解标注,表示这个接口被设计成函数式接口,只能有一个抽象方法,如果你添加多个抽象方法,编译时会提示“Multiple non-overriding abstract methods found in interface XXX”之类的错误。
标注为 FunctionalInterface 的接口被称为函数式接口,该接口只能有一个自定义方法,但是可以包括从 object 类继承而来的方法。如果一个接口只有一个方法,则编译器会认为这就是一个函数式接口。是否是一个函数式接口,需要注意的有以下几点:
该注解只能标记在”有且仅有一个抽象方法”的接口上。
JDK8 接口中的静态方法和默认方法,都不算是抽象方法。
接口默认继承 java.lang.Object,所以如果接口显示声明覆盖了 Object 中方法,那么也不算抽象方法。
该注解不是必须的,如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
在一个接口中定义两个自定义的方法,就会产生 Invalid ‘@FunctionalInterface’ annotation; FunctionalInterfaceTest is not a functional interface 错误.
Java8 允许你以 Lambda 表达式的方式为函数式接口提供实现, 「 通俗的说,你可以将整个 Lambda 表达式作为接口的实现类 」 。
除了 Runnable
之外,Java 8 中内置了许多函数式接口供开发者使用,这些接口位于 java.util.function
包中。如:
name | type | result | desc |
---|---|---|---|
Consumer | Consumer | T -> void | 接收 T 对象,不返回值 |
Predicate | Predicate | T -> boolean | 接收 T 对象并返回 boolean |
Function | Function<T, R> | T -> R | 接收 T 对象,返回 R 对象 |
Supplier | Supplier | void -> T | 提供 T 对象(例如工厂),不接收值 |
UnaryOperator | UnaryOperator | T -> T | 接收 T 对象,返回 T 对象 |
BinaryOperator | BinaryOperator | T, T -> T | 接收两个 T 对象,返回 T 对象 |
如果输入参数是基本类型,为了避免自动拆箱装箱,可以使用其他基本类型的函数接口。
Function
interface Function<T, R>
接口包含一个 apply
方法、两个默认方法( compose
、 andThen
)和一个静态方法 identity
。 apply
是接口的基本方法。 compose
、 andThen
是一对儿方法,他们的区别在于执行的顺序不同。
//返回一个先执行before函数对象apply方法再执行当前函数对象apply方法的函数对象 default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } 复制代码
//返回一个先执行当前函数对象apply方法再执行after函数对象apply方法的函数对象。 default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } 复制代码
// 根据上面的解释想一下执行结果 Function<Integer, Integer> name = e -> e * 2; Function<Integer, Integer> square = e -> e * e; int value = name.andThen(square).apply(3); int value2 = name.compose(square).apply(3); //返回一个执行了apply()方法之后只会返回输入参数的函数对象 Object identity = Function.identity().apply("Test"); 复制代码
Consumer
interface Consumer<T>
接口包含一个 void accept(T t);
方法、默认方法 andThen
.
default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } 复制代码
只有一个默认方法也是和它的返回类型有关系,因为返回的是 void。
Predicate
interface Predicate<T>
接口包含一个 boolean test(T t);
方法,三个默认方法( and
, negate
, or
),还有一个静态方法。 我们也知道 Predicate 接口是返回 boolean 类型的,所以一看就知道是条件判断的。 举几个栗子吧:
String name = "hello"; Predicate<String> predicate = x -> x.equals("hello"); Predicate<String> predicate2 = x -> x.length() < 2; // and 多个Predicate条件并的关系判断,第一个为false就不往下走了,满足短路原则 System.out.println(predicate.and(predicate2).test(name)); // or 多个Predicate条件或的关系判断,同样满足短路原则 System.out.println(predicate.or(predicate2).test(name)); // negate 取反的意思,就是否的条件判断 System.out.println(predicate.and(predicate2.negate()).test(name)); // isEqual 静态方法,判断是否相等 System.out.println(Predicate.isEqual(name).test(name)); 复制代码
Supplier
Supplier
只有一个 get()方法。 我们来看看几个栗子:
Supplier<String> supplier = () -> "hello world"; //get方法不接受参数,返回一个结果 System.out.println("supplier = [" + supplier.get() + "]"); //替代不接受参数的工厂方法 Supplier<Student> studentSupplier = () -> new Student(); System.out.println(studentSupplier.get()); //因为Student的构造方法不接受参数,返回一个结果,符合Supplier接口的要求,可以简写如下: Supplier<Student> studentSupplier2 = Student::new; 复制代码
函数式接口其实差别不大,只是参数和返回的不同,只要想明白其中的一种,其他的也就懂了。
JDK8 新特性-java.util.function-Function 接口 [1]
Java8 的一些新特性 java.util.function 包 [2]
Java JVM(七):Function,Consumer,Predicate 接口 [3]
求关注、分享、在看!!! 你的支持是我创作最大的动力。