如果你的好奇心使你翻看Runnable
接口源代码,你会发现该接口被一个@FunctionalInterface
的注解修饰,这是Java 8中添加的新注解,用于表示 函数式接口。
在Java 8中,把那些仅有一个抽象方法的接口称为函数式接口。如果一个接口被@FunctionalInterface
注解标注,表示这个接口被设计成函数式接口,只能有一个抽象方法,如果你添加多个抽象方法,编译时会提示“Multiple non-overriding abstract methods found in interface XXX”之类的错误。
标注为FunctionalInterface的接口被称为函数式接口,该接口只能有一个自定义方法,但是可以包括从object类继承而来的方法。如果一个接口只有一个方法,则编译器会认为这就是一个函数式接口。是否是一个函数式接口,需要注意的有以下几点:
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对象 |
Supplier | Supplier | void -> T | 提供T对象(例如工厂),不接收值 |
UnaryOperator | UnaryOperator | T -> T | 接收T对象,返回T对象 |
BinaryOperator | BinaryOperator | T, T -> T | 接收两个T对象,返回T对象 |
如果输入参数是基本类型,为了避免自动拆箱装箱,可以使用其他基本类型的函数接口。
Function
interface Function
接口包含一个apply
方法、两个默认方法(compose
、andThen
)和一个静态方法identity
。
apply
是接口的基本方法。
compose
、andThen
是一对儿方法,他们的区别在于执行的顺序不同。
//返回一个先执行before函数对象apply方法再执行当前函数对象apply方法的函数对象
default Function compose(Function super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
//返回一个先执行当前函数对象apply方法再执行after函数对象apply方法的函数对象。
default Function andThen(Function super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
// 根据上面的解释想一下执行结果
Function name = e -> e * 2;
Function 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
接口包含一个void accept(T t);
方法、默认方法andThen
.
default Consumer andThen(Consumer super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
只有一个默认方法也是和它的返回类型有关系,因为返回的是void。
Predicate
interface Predicate
接口包含一个boolean test(T t);
方法,三个默认方法(and
,negate
,or
),还有一个静态方法。
我们也知道Predicate接口是返回boolean类型的,所以一看就知道是条件判断的。
举几个栗子吧:
String name = "hello";
Predicate predicate = x -> x.equals("hello");
Predicate 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 supplier = () -> "hello world";
//get方法不接受参数,返回一个结果
System.out.println("supplier = [" + supplier.get() + "]");
//替代不接受参数的工厂方法
Supplier studentSupplier = () -> new Student();
System.out.println(studentSupplier.get());
//因为Student的构造方法不接受参数,返回一个结果,符合Supplier接口的要求,可以简写如下:
Supplier studentSupplier2 = Student::new;
函数式接口其实差别不大,只是参数和返回的不同,只要想明白其中的一种,其他的也就懂了。
参考
JDK8新特性-java.util.function-Function接口
Java8的一些新特性 java.util.function包
Java JVM(七):Function,Consumer,Predicate 接口