Why can't I use Stream#toList to collect a list of a class' interface in Java 16?
17
I'm streaming objects of a class implementing an interface. I'd like to collect them as a list of elements of the interface, rather than the implementing class.
This seems impossible with Java 16.0.1's Stream#toList method. For example in the code below, the last statement will fail to compile.
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class WhyDodo {
private interface Dodo { }
private static class FancyDodo implements Dodo { }
public static void main(String[] args) {
final List<Dodo> dodos = Stream.of(new FancyDodo()).collect(Collectors.toList());
final List<FancyDodo> fancyDodos = Stream.of(new FancyDodo()).toList();
final List<Dodo> noFancyDodos = Stream.of(new FancyDodo()).toList();
}
}
We could explicitly cast each element from FancyDodo to Dodo. But at least for brevity, we could just as well use .collect(Collectors.toList()).
Why can't I use Stream#toList to collect a list of a class' interface in Java 16?
And if anyone has a better solution than explicitly casting, I'd be happy to hear as well :)
java generics java-stream type-inference java-16
Stream.<Dodo>of(new FancyDodo()). With that factory method, you getStream<FancyDodo>, which is not compatible withStream<Dodo>– ernest_k May 13 at 10:01.collect(Collectors.toList())unless the documentation could call that out. Another interesting line isfinal List<Dodo> fancyDodosAgain = Arrays.asList(Stream.of(new FancyDodo()).toArray(Dodo[]::new))– Naman May 13 at 10:09List<T>, whereTis whatever it is a stream of. If you want a more abstract type, that's easy:List<Dodo> dodos = fancyDodos.stream().map(d -> (Dodo) d).toList()– Brian Goetz May 13 at 18:00List<? extends Dodo> = fancyDodos.stream().toList(), since aList<FancyDodo>is aList<? extends Dodo>. – Brian Goetz May 13 at 18:53<U super T> List<U> toList()). This syntax does not exist because when Generics were introduced, the creators thought that this was rarely needed. It works withcollect, because thetoListcollector introduces its own type variable which gets mapped to the Stream’s type parameter with asuperbound at thecollectcall. Edit: oh, just saw this comment… – Holger 17 hours ago