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>
.
Optional<T>.orElseGet
is specified to accept aSupplier<? extends T>
. But the meaning ofOptional<? extends SomeValue>
is that it could be anOptional<MySubClassOfSomeValue>
, in which case aSupplier<SomeValue>
would not be aSupplier<? extends MySubClassOfSomeValue>
.orElseGet
must return a subtype of the element type of theOptional
, and? extends SomeValue
may be something other thanSomeValue
.This is the result of a rather restricted method signature:
In your case,
T
is? extends SomeValue
which is an unknown type being assignable toSomeValue
(but may be a subclass of it). The signature oforElseGet
implies that your supplier is allowed to return a subtype ofT
, having the overall result type ofT
but it does not allow to do a widening to a common base type ofT
and the type your supplier returns (If your supplier returnsSomeValue
andT
is? extends SomeValue
, the common base type would beSomeValue
).You can fix this by inserting an operation which allows widening of the type:
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 consumeSomeValue
when the actual input type is? extends SomeValue
and the return type isSomeValue
.But generally, to avoid such problems, methods should not have wildcards in their return types, so change
to
See http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html