Home > Enterprise >  Why Stream.generate use non-variance, but Optional.orElseGet use Covariance in Java 8
Why Stream.generate use non-variance, but Optional.orElseGet use Covariance in Java 8

Time:12-03

For Java 8 source code in Stream class:

public static<T> Stream<T> generate(Supplier<T> s) {
        ...
}

In Optional class

public T orElseGet(Supplier<? extends T> other) {
    ...
}

I already read this post: PECS, but I have some confusison.

Why generate method parameter(Supplier<T> s) use non-variance, but orElseGet method parameter(Supplier<? extends T> other) use Covariance, how to decide use Covariance or non-variance?

CodePudding user response:

Looks like the Java developers agreed with you that generate should accept Supplier<? extends T>, as it was changed in Java 9. See JDK-8132097 (Stream.generate should use a covariant Supplier as parameter):

Description

The signature of Stream.generate doesn't to use a wildcard (? extends) hence some programs are rejected even if they are valid. The signature should be public static Stream generate(Supplier<? extends T> s).

The change makes sense, as doing something like the this:

Stream<CharSequence> stream = Stream.generate(new Supplier<String>() {
    @Override public String get() {
      // implementation...
    }
});

Should be perfectly valid. Admittedly, that is a very contrived example, but the point stands: The Supplier should be allowed to be parameterized with any subtype of T. And to relate this to PECS, the Supplier is functioning as a producer of T.

CodePudding user response:

The elements of a Stream can be both consumed (e.g. by calling forEach(Consumer<T>...)) and produced (e.g. by collecting them to a List). If the generate(...)-method would have a Supplier<? extends T>-parameter, then collect(Collectors.toList()) would - for example - return a List<? extends T>, which would prevent us from assigning it to a List<? super T>. With a parameter of type Supplier<T>, the above is possible.

For Optional.orElseGet(...), it is always a producer. Even if we have a U extends T, we can still safely write something like U u = Optional.ofNullable(someU).orElseGet(this::someT);.

  • Related