如何编写一种方法,使用Consumer.andThen(Consumer)将消费者流组合成单个消费者?
我的第一个版本是:
Consumer combine(Stream> consumers) {
return consumers
.filter(Objects::nonNull)
.reduce(Consumer::andThen)
.orElse(noOpConsumer());
}
Consumer noOpConsumer() {
return value -> { /* do nothing */ };
}
此版本使用JavaC和Eclipse编译.但它太具体了:Stream不能是Stream< SpecialConsumer>,如果消费者不完全是T型但是它的超类型,它就不能使用:
Stream extends Consumer super Foo>> consumers = ... ;
combine(consumers);
这不会合理地编译.改进版将是:
Consumer combine(Stream extends Consumer super T>> consumers) {
return consumers
.filter(Objects::nonNull)
.reduce(Consumer::andThen)
.orElse(noOpConsumer());
}
但Eclipse和JavaC都没有编译:
Eclipse(4.7.3a):
The type Consumer does not define andThen(capture#7-of ? extends Consumer super T>, capture#7-of ? extends Consumer super T>) that is applicable here
JavaC(1.8.0172):
error: incompatible types: invalid method reference
.reduce(Consumer::andThen)
incompatible types: Consumer cannot be converted to Consumer super CAP#2>
where T is a type-variable:
T extends Object declared in method combine(Stream extends Consumer super T>>)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object super: T from capture of ? super T
CAP#2 extends Object super: T from capture of ? super T
但它应该有效:消费者的每个子类也可以用作消费者.每个X型超级消费者也可以消费X.我尝试将类型参数添加到流版本的每一行,但这无济于事.但如果我用传统的循环写下来,它会编译:
Consumer combine(Collection extends Consumer super T>> consumers) {
Consumer result = noOpConsumer()
for (Consumer super T> consumer : consumers) {
result = result.andThen(consumer);
}
return result;
}
(为简明起见,省略了过滤掉空值.)
因此,我的问题是:我怎样才能说服JavaC和Eclipse我的代码是正确的?或者,如果不正确:为什么循环版本正确但不是流版本?