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);
.