I am trying to use Optional.or
to get an object of subclass A or, if empty, an object of subclass B:
interface Node {}
class InnerNode implements Node {}
class LeafNode implements Node {}
Optional<InnerNode> createInnerNode() {}
Optional<LeafNode> createLeafNode() {}
Optional<Node> node = createInnerNode().or(() -> createLeafNode());
When doing this, I get the following compiler error:
Bad return type in lambda expression: Optional<LeafNode> cannot be converted to Optional<? extends InnerNode>
If I instead use wildcards to explicitly tell the compiler that the Optionals contain an object extending from Node
:
Optional<? extends Node> optionalInner = createInnerNode();
Optional<? extends Node> optionalLeaf = createLeafNode();
Optional<Node> node = optionalInner.or(() -> optionalLeaf);
I get the following compiler error:
Bad return type in lambda expression: Optional<capture of ? extends Node> cannot be converted to Optional<? extends capture of ? extends Node>
The only way I found to make this work, is using an Optional.empty
in front:
Optional<Node> node = Optional.<Node>empty() // requires generic argument
.or(() -> createInnerNode())
.or(() -> createLeafNode());
But for me, this is confusing to read. Is it somehow possible to instruct the compiler to allow the statement optionalInner.or(() -> optionalLeaf)
? Or are there other alternatives to make this work?
The workaround you provided is a pretty simple answer, but you can convert an
Optional<InnerNode>
to anOptional<Node>
trivially with map if you want to avoid a placeholder Optional.In general, this is also how you conceptually turn a
List<Dog>
to aList<Animal>
or any generic collection to a different generic collection in java as well. It's somewhat annoying, but wildcards don't cut it because you want both read/write on the transformed collection.The signature of or should tell you why your workaround works
notice how it's already using the ? extends T in the supplier. Since the first empty Optional's T is Node, the or function can accept a supplier that returns
and since both the innernode and leafnode are an
Optional<? extends Node>
, this works.So the problem is that you need an
Optional<Node>
at some point.I don't think you can avoid doing something since an
Optional<InnerNode>
never type matchesOptional<Node>
for reasons listed in other answers (and other questions on stack overflow).Reading the other answer and trying
means that the T is a
which makes
or
seem to want doubly nested captures? I can't stop gettingwhen trying basically any cast with the following code