Java Consumer接口,用户希望编写实现 java.util.function.Consumer
包的 lambda 表达式,可以使用 lambda 表达式或方法引用来实现 void accept(T t)
方法。例 2-1 列出了 Consumer
接口定义的方法,其单一抽象方法为 void accept(T t)
。
Java Consumer接口 问题描述
用户希望编写实现 java.util.function.Consumer
包的 lambda 表达式。
Java Consumer接口 解决方案
使用 lambda 表达式或方法引用来实现 void accept(T t)
方法。
Java Consumer接口 具体实例
例 2-1 列出了 Consumer
接口定义的方法,其单一抽象方法为 void accept(T t)
。
例 2-1
Consumer
接口定义的方法
void accept(T t) ➊
default Consumer<T> andThen(Consumer<? super T> after) ➋
❶ 单一抽象方法
❷ 用于复合操作的默认方法
accept
方法传入一个泛型参数并返回 void
。在所有传入 Consumer
作为参数的方法中,最常见的是 java.util.Iterable
接口的默认 forEach
方法,如例 2-2 所示。
例 2-2
Iterable
接口定义的forEach
方法
default void forEach(Consumer<? super T> action) ➊
➊ 将可迭代集合(iterable collection)中的所有元素传递给 Consumer
参数
如例 2-3 所示,所有线性集合通过对集合中每个元素执行给定的操作来实现 Iterable
接口。
例 2-3 打印集合中的元素
List<String> strings = Arrays.asList("this", "is", "a", "list", "of", "strings");
strings.forEach(new Consumer<String>() { ➊
@Override
public void accept(String s) {
System.out.println(s);
}
});
strings.forEach(s -> System.out.println(s)); ➋
strings.forEach(System.out::println); ➌
❶ 匿名内部类实现
❷ lambda 表达式
❸ 方法引用
在本例中,由于 accept
方法只传入一个参数且不返回任何值,其签名与 lambda 表达式相符。通过 System.out
访问 PrintStream
类的 println
方法,它与 Consumer
相互兼容。因此,最后两条语句都可以作为 Consumer
参数的目标。
如表 2-1 所示,java.util.function
包还定义了三种 Consumer<T>
的基本变体,以及一种双参数形式。
表2-1:其他Consumer
接口
接口 | 单一抽象方法 |
---|---|
IntConsumer |
void accept(int x) |
DoubleConsumer |
void accept(double x) |
LongConsumer |
void accept(long x) |
BiConsumer |
void accept(T t, U u) |
Consumer
接口期望执行带有副作用的操作(即它可能会改变输入参数的内部状态),参见范例 Predicate接口
BiConsumer
接口的 accept
方法传入两个泛型参数,这两个泛型参数应为不同的类型。java.util.function
包定义了 BiConsumer
接口的三种变体,每种变体的第二个参数为基本数据类型。以 ObjIntConsumer
接口为例,其 accept
方法传入两个参数,分别为泛型参数和 int
参数。ObjLongConsumer
和 ObjDoubleConsumer
接口的定义与 ObjIntConsumer
类似。
标准库还支持 Consumer
接口的一些其他用法。
Optional.ifPresent(Consumer<? super T> consumer)
如果值存在,则调用指定的 consumer
;否则不进行任何操作。
Stream.forEach(Consumer<? super T> action)
对流的每个元素执行操作 1。Stream.forEachOrdered
方法与之类似,它根据元素的出现顺序(encounter order)访问元素。
1这项操作十分常见,因此 Iterable
接口也直接定义了 forEach
方法。当源元素不是来自集合或需要创建并行流时,Stream.forEach
方法就很有用。
Stream.peek(Consumer<? super T> action)
首先执行给定操作,再返回一个与现有流包含相同元素的流。peek
方法在调试中极为有用(参见范例 利用peek方法对流进行调试)。