- 前言
- Consumer
- Supplier
- Function
- Predicate
- 总结
前言
功能接口是指只有一个抽象方法的接口,功能接口只能有一个抽象方法,但是可以有多个默认方法和 静态方法 。一个功能接口可以被注解FunctionalInterface注释,一旦被FunctionalInterface注解注释,当这个功能接口有多个抽象方法时编译器就会报错。
基于只有一个抽象方法的接口使用匿名类时,会使代码看上去很臃肿,针对这个问题lambda表达式应运而生。要想使用lambda表达式首先必须要有一个对应的功能接口。
jdk 里面有一些内置的功能接口,这些内置的功能接口在实际开发过程中开发人员可以根据不同的场景直接使用。
Consumer
java.util.function.Consumer接口的功能方法为accept,接收一个参数,没有返回值。意思就是只消费数据,不生产数据。
泛型 接口,定义如下:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
- accept方法为该功能接口的功能方法,只接收数据,不返回数据,用法如下:
- andThen为一个默认方法,接收一个 Consumer 类型的表达式,返回一个Consumer类型的表达式,只不过返回的表达式执行时会随后把传入的表达式也执行一次。示例如下,当accept方法传入参数1时,除了会打印一下1,还会把后面添加的lambda表达式按照先后顺序执行一遍。最后一个andThen传入的表达式在最后执行。
andThen方法的设计意图只要是为了让通过andThen方法添加的后续的lambda表达式,都可以对同一个参数依次进行处理。
Consumer类型的功能接口还有:
- java.util.function.BiConsumer,泛型接口,其accept方法接收消费2个参数,没有返回值。
void accept(T t, U u);
- java.util.function.DoubleConsumer,其accept方法接收消费一个double类型的参数,没有返回值。
void accept(double value);
- java.util.function.IntConsumer,其accept方法接收消费一个int类型的参数,没有返回值。
void accept(int value);
- java.util.function.LongConsumer,其accept方法接收消费一个long类型的参数,没有返回值。
void accept(long value);
- java.util.function.ObjDoubleConsumer,泛型接口,其accept方法接收消费1个泛型参数和1个double类型的参数,没有返回值。
void accept(T t, double value);
- java.util.function.ObjIntConsumer,泛型接口,其accept方法接收消费1个泛型参数和1个int类型的参数,没有返回值。
void accept(T t, int value);
- java.util.function.ObjLongConsumer,泛型接口,其accept方法接收消费1个泛型参数和1个long类型的参数,没有返回值。
void accept(T t, long value);
Supplier
java.util.function.Supplier接口的功能方法为get,不接收入参,但是会有返回值。意思就是只生产数据,不消费数据。
泛型接口,定义如下:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
- get方法为该功能接口的功能方法,示例如下:
示例当中,supplier通过方法引用提供了一个Set集合的对象,第8行通过get方法拿到这个Set对象,随后添加两个数字并打印。
Supplier功能接口可以作为一个工厂来用,因为它们在对外提供对象而又不对外提供对象的创建过程这一点上是相同的。
Supplier类型的功能接口还有:
- java.util. function . boolean Supplier,功能方法返回一个boolean类型的结果。
boolean getAsBoolean();
- java.util.function.DoubleSupplier,功能方法返回一个double类型的结果。
double getAsDouble();
- java.util.function.IntSupplier,功能方法返回一个int类型的结果。
int getAsInt();
- java.util.function.LongSupplier,功能方法返回一个long类型的结果。
long getAsLong();
Function
java.util.function.Function接口的功能方法为apply,接收一个参数并且有返回值。意思就是消费一个数据也生产一个数据。
泛型接口,定义如下:
@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;
}
}
- apply方法为功能方法,下图示例中function表达式对输入的参数加上1000,然后转换为String类型并返回。传入的数字为120,控制台打印结果为1120。
- andThen方法同Consumer的andThen方法类似,会在一个lambda表达式后面添加额外的操作。不同的是Function中的后续表达式会使用前面表达式的结果作为输入。下图示例中一共执行了4个lambda表达式,第一个表达式把参数原封不动地返回,后面的表达式依次会对前面操作的结果加10、加100、加1000。apply方法传入参数1,最终结果为1111。
Function类型的接口更加丰富,具体可见包java.util.function下的以Function结尾的功能接口。
Predicate
java.util.function.Predicate接口的功能方法为test,接收一个参数,返回一个boolean类型的结果。主要是根据传入的参数进行判断。Predicate英文含义为断言,属于谓词,表示是和否。
泛型接口,定义如下:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
- test方法为功能方法,如下示例中主要判断输入的 Integer 类型的参数是否等于110。代码第6行传入数字110,可以看到控制台打印了结果为true。
- and方法和or方法类似,都是接收一个Predicate类型的表达式,只不过and方法表示本lambda表达式和接收的参数表达式是同时成立的意思,or方法表示的是本lambda表达式和参数表达式是逻辑或的意思。
总结
- Consumer只消费数据,不生产数据;
- Supplier只提供数据,不消费数据,可以作为工厂使用;
- Function即消费数据,也生产数据;
- Predicate断言,根据输入的数据判断结果是否为true
功能接口在jdk、开源框架和一些工具包中已经应用得很普遍了,了解并熟悉java.util.function包中的功能接口即能够帮助我们快速读懂这些源码,也能够简化我们的开发。