Why Stream.concat is a static method - type variable contravariance

James Roper james at lightbend.com
Thu Oct 11 04:06:23 UTC 2018

With the work I'm doing at the moment at creating a Reactive Streams
equivalent to java.util.stream, I've often wondered why Stream.concat is a
static method, rather than an instance method concating the given stream
onto this. But I think the reason has just dawned on me, and I wanted to
confirm that I'm correct.

Java doesn't support contravariant type variables - it does for type
declarations, but not type variables.

To put more concretely, if I had a Stream<Integer>, and I wanted to concat
a Stream<Number>, this is a valid thing to do, the resulting stream would
be Stream<Number>. But doing that with an instance method would require
something like this:

public <S super T> Stream<S> concat(Stream<? extends S> b);

Which is not supported (specifically, <S super T> type variable declaration
is not supported). In contrast, what we have in the actual API:

public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends
T> b);

does allow me to concat a Stream<Integer> and Stream<Number> with a
resulting type of Stream<Number>.

Is this right, or are there other reasons? Also, is there any possibility
that Java might support contravariance in type variables in future? My
reason for wanting it is to provide the following method for reactive

public <S super T> Publisher<S> onErrorResumeWith(Function<? super
Throwable, ? extends Publisher<? extends S>> f);

The intent of this method is when a stream encounters an error, the passed
function is invoked with the error, and that function returns a publisher
that gets concated to the current stream instead of the error being
emitted. This could possibly be implemented with a static method:

public static <T> Publisher<T> onErrorResumeWith(Publisher<? extends T> a,
Function<? super Throwable, ? extends Publisher<? extends T> f);

But unlike concat, this method feels and reads much better as an instance
method, as a static method it's a little confusing.



*James Roper*
*Senior Developer, Office of the CTO*

Lightbend <https://www.lightbend.com/> – Build reactive apps!
Twitter: @jroper <https://twitter.com/jroper>

More information about the core-libs-dev mailing list