Optional<> and return type narrowing
Asked Answered
P

2

9

In Java < 8, returning "unsafe" objects (objects or null), I was able to specialize return type in subclass:

class A {}
class B extends A {}
interface Sup { A a(); /* returns A instance, or null */ }
interface Sub extends Sup { B a(); }

In Java 8, if I want to make my API "safer", I should return Optional<A> instead of "raw" A:

interface Sup { Optional<A> a(); }
interface Sub extends Sup { Optional<B> a(); }

But doesn't compile! Because Optional<B> is not a subclass of Optional<A>.

How I'm supposed to resolve this issue?

Pipsqueak answered 25/4, 2015 at 19:13 Comment(0)
P
10

You could use wildcards.

interface Sup { Optional<? extends A> a(); }

interface Sub extends Sup { Optional<? extends B> a(); }

I could have made it just Optional<B> but using Optional<? extends B> allows another interface to extend Sub and do the same thing.

Personally, I think this is a bit of a mess, and it would be preferable to just return A or B, or null where necessary.

Passable answered 25/4, 2015 at 19:21 Comment(5)
There are schools of thought which believe that shifting to the Optional paradigm produces fewer NPEs, and forces one to reason better about what behaviors the code actually has.Neoma
@Neoma I know the arguments, and I agree with them (I use Optional all the time). My comment at the end was about combining ? and OptionalPassable
Using the upper bound isn't the worst thing that could happen; there may be very justifiable reasons as to why one would do that. The reason I reacted the way I did was because you had mentioned null.Neoma
@Neoma You never return null?Passable
While I think that this is getting a bit too chatty, I don't return null where I can help it - where I have access to use Optional, either with Guava or with Java 8, I elect to use this pattern instead of null.Neoma
N
2

Change your parent bounds to use wildcards:

Optional<? extends A> // parent
Optional<? extends B> // child

The reason that your code doesn't work now is due to the fact that generics are invariant. B is-an A, but Optional<B> is not an Optional<A>.

Neoma answered 25/4, 2015 at 19:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.