Why does this not compile? :
import java.util.Optional;
public class Demo {
Optional<? extends SomeValue> getOption() {
return Optional.empty();
}
void exposure() {
SomeValue someValue = getOption().orElseGet(() -> new SomeValue());
}
}
class SomeValue {}
It works without problem when getOption()
would return a Optional<SomeValue>
.
This is the result of a rather restricted method signature:
public T orElseGet(Supplier<? extends T> other) {
In your case, T
is ? extends SomeValue
which is an unknown type being assignable to SomeValue
(but may be a subclass of it). The signature of orElseGet
implies that your supplier is allowed to return a subtype of T
, having the overall result type of T
but it does not allow to do a widening to a common base type of T
and the type your supplier returns (If your supplier returns SomeValue
and T
is ? extends SomeValue
, the common base type would be SomeValue
).
You can fix this by inserting an operation which allows widening of the type:
SomeValue someValue = getOption()
.map(Function.<SomeValue>identity()).orElseGet(() -> new SomeValue());
The identity
function does not change the value, but the mapping operation allows to pass in a function consuming a broader type, i.e. the mapping function may declare to consume SomeValue
when the actual input type is ? extends SomeValue
and the return type is SomeValue
.
But generally, to avoid such problems, methods should not have wildcards in their return types, so change
Optional<? extends SomeValue> getOption()
to
Optional<SomeValue> getOption()
See http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html
Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards.
Optional<T>.orElseGet
is specified to accept a Supplier<? extends T>
. But the meaning of Optional<? extends SomeValue>
is that it could be an Optional<MySubClassOfSomeValue>
, in which case a Supplier<SomeValue>
would not be a Supplier<? extends MySubClassOfSomeValue>
.
orElseGet
must return a subtype of the element type of the Optional
, and ? extends SomeValue
may be something other than SomeValue
.