What is the type of an Optional created from a constant different to one created from a stream? [duplicate]
Let's say I have an interface Bar
and an implementing class Foo
:
interface Bar { ... }
class Foo implements Bar {
static final Foo X = new Foo();
static final Foo Y = new Foo();
static final Foo[] FOOS = { X, Y };
}
Now let's say I have a class with methods that return Optional<Bar>
:
public class Fubar {
public Optional<Bar> fromValue() {
return Optional.of(Foo.X); // This is fine
}
public Optional<Bar> fromStreamA() {
Optional<Foo> foo = Arrays.asList(Foo.FOOS).stream().findFirst();
return foo; // This fails to compile
}
public Optional<Bar> fromStreamB() {
Optional<Foo> foo = Arrays.asList(Foo.FOOS).stream().findFirst();
if (foo.isPresent()) {
return Optional.of(foo.get()); // This is also fine
}
return Optional.empty();
}
}
The method fromValue()
compiles correctly, however fromStreamA()
does not. I get an error message along the lines of Type mismatch: cannot convert from Optional<Foo> to Optional<Bar>
. I worked around this mismatch in fromStreamB()
(which compiles correctly).
I'm having trouble understanding why fromStreamA()
does not compile. I sense it's something to do with generics and is similar to why List<Foo>
cannot be assigned to List<Bar>
, however I can't grasp it. Can anyone explain why fromValue()
is fine and fromStreamA()
is not.
It's because generics are not covariant: Optional<Foo>
cannot be assigned to an Optional<Bar>
.
The other example works because the compiler helps you infer the type to be Bar
, i.e.:
Optional.of(Foo.X)
is equivalent to:
Optional.<Bar>of(Foo.X)
If you try to explicitly tell the inferred type to the compiler, it will not accept it:
Optional.<Foo>of(Foo.X); // does not compile