Java 8 泛型:将一个使用者流减少到单个使用者
如何编写将 a 组合成单个使用的方法?Stream
Consumers
Consumer
Consumer.andThen(Consumer)
我的第一个版本是:
<T> Consumer<T> combine(Stream<Consumer<T>> consumers) {
return consumers
.filter(Objects::nonNull)
.reduce(Consumer::andThen)
.orElse(noOpConsumer());
}
<T> Consumer<T> noOpConsumer() {
return value -> { /* do nothing */ };
}
这个版本使用JavaC和Eclipse编译。但它太具体了:不能是 ,如果 不是确切的类型,而是它的超类型,则不能使用它:Stream
Stream<SpecialConsumer>
Consumers
T
Stream<? extends Consumer<? super Foo>> consumers = ... ;
combine(consumers);
这是理所当然的,不会编译。改进的版本将是:
<T> Consumer<T> combine(Stream<? extends Consumer<? super T>> consumers) {
return consumers
.filter(Objects::nonNull)
.reduce(Consumer::andThen)
.orElse(noOpConsumer());
}
但是 Eclipse 和 JavaC 都没有编译:
Eclipse (4.7.3a):
类型未定义此处适用的类型
Consumer
andThen(capture#7-of ? extends Consumer<? super T>, capture#7-of ? extends Consumer<? super T>)
JavaC (1.8.0172):
错误:不兼容类型:无效方法引用
不兼容类型:无法转换为
where 是类型变量:
在方法
中声明,其中 是新鲜的类型变量:.reduce(Consumer::andThen)
Consumer<CAP#1>
Consumer<? super CAP#2>
T
T extends Object
<T>combine(Stream<? extends Consumer<? super T>>)
CAP#1
CAP#2
CAP#1 extends Object super: T from capture of ? super T
CAP#2 extends Object super: T from capture of ? super T
但它应该有效:Consumer的每个子类也可以用作Consumer。每个超类型X的消费者也可以消费X。我试图将类型参数添加到流版本的每行,但这无济于事。但是如果我用一个传统的循环把它写下来,它会编译:
<T> Consumer<T> combine(Collection<? extends Consumer<? super T>> consumers) {
Consumer<T> result = noOpConsumer()
for (Consumer<? super T> consumer : consumers) {
result = result.andThen(consumer);
}
return result;
}
(为了简洁起见,省略了筛选出 null 值。
因此,我的问题是:我如何说服JavaC和Eclipse我的代码是正确的?或者,如果它不正确:为什么循环版本是正确的,而不是版本?Stream