Comment puis-je écrire une méthode pour combiner une Stream
de Consumers
en une seule, Consumer
l'aide Consumer.andThen(Consumer)
?
Ma première version était:
<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 */ };
}
Cette version compile avec JavaC et Eclipse. Mais il est trop spécifique: L' Stream
ne peut pas être un Stream<SpecialConsumer>
, et si l' Consumers
ne sont pas exactement du type T
mais un super type, il ne peut pas être utilisé:
Stream<? extends Consumer<? super Foo>> consumers = ... ;
combine(consumers);
Qui ne compile pas, à juste titre. La version améliorée serait:
<T> Consumer<T> combine(Stream<? extends Consumer<? super T>> consumers) {
return consumers
.filter(Objects::nonNull)
.reduce(Consumer::andThen)
.orElse(noOpConsumer());
}
Mais ni l'Éclipse, ni compilation JavaC que:
Eclipse (4.7.3 un):
Le type
Consumer
ne définit pasandThen(capture#7-of ? extends Consumer<? super T>, capture#7-of ? extends Consumer<? super T>)
qui est applicable ici
JavaC (1.8.0172):
error: incompatible types: invalid méthode de référence
.reduce(Consumer::andThen)
des types incompatibles:Consumer<CAP#1>
ne peut pas être convertieConsumer<? super CAP#2>
oùT
est un type de variable:T extends Object
déclaré dans la méthode<T>combine(Stream<? extends Consumer<? super T>>)
oùCAP#1
,CAP#2
sont neuves par type de variables:CAP#1 extends Object super: T from capture of ? super T
CAP#2 extends Object super: T from capture of ? super T
Mais cela devrait fonctionner: Chaque sous-classe de Consommateur peut être utilisé en tant que Consommateur, trop. Et tous les Consommateurs d'un super-type de X peut consommer Xs, trop. J'ai essayé d'ajouter des paramètres de type pour chaque ligne du flux version, mais ça n'aide pas. Mais si je l'écris avec un traditionnel de la boucle, il compile:
<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;
}
(Le filtrage des valeurs null est laissée de côté pour alléger le texte.)
Donc, ma question est: Comment puis-je convaincre JavaC et Eclipse que mon Code est correct? Ou, si il n'est pas correct: Pourquoi la boucle-version correcte, mais pas l' Stream
Version?