Java 8 中提供了四种原生函数式接口,分别是 Consumer(消费型) 、 Supplier(供给型) 、 Predicate(断言型) 、Function(功能型) 。
今天先来聊一聊 Consumer 接口。
Consumer
顾名思义,这是个消费型的接口,可以实现对数据的消费。先看接口定义:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
可以看到,接口定义上有一个 @FunctionalInterface 注解。
@FunctionalInterface 注解是一个标记函数式接口的注解,作用类似于 @Override 接口,可以强制编译器检查接口是否有且只有一个抽象方法。
有且只有一个抽象方法的接口被称为函数式接口, @FunctionalInterface 注解并不是必须的,只要是符合函数式接口的定义,就是函数式接口。
接着往下看, consumer接口有且只有一个accept 方法, accept 方法通过泛型 <T> 定义了一个入参,没有返回值,我们在实现一个 Consumer 接口的时候,可以通过实现 accept 方法,作为消费者对数据进行消费。
通常,我们都结合 Stream 和 Lambda 进行使用,Stream 中的 forEach 方法的参数就是一个 Consumer 接口
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
可以看出, forEach 方法就是调用了传入的 Consumer 接口的 accept 方法对数据进行消费,我们可以通过实现 accept 方法,对数据进行自定义消费处理。
举个例子,如果我们要对 List 中的数据进行遍历并拼接上前后缀并输出,我们可以使用 Consumer 结合 forEach 处理
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
Consumer<Integer> consumer = new Consumer<>() {
@Override
public void accept(Integer integer) {
System.out.println("打印 " + integer + " 成功");
}
};
list.forEach(consumer);
}
输出结果
打印 1 成功
打印 2 成功
打印 3 成功
打印 4 成功
打印 5 成功
我们还可以通过结合 Lambda 表达式,通过极简的代码完成操作
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
list.forEach(i -> System.out.println("打印 " + i + " 成功"));
}
合理运用函数式接口和 Lambda 、Stream 可以极大提升我们的编码效率,用过的人都知道,丝般顺滑!