How to upcast object contained in Java 8 Optional?

I would write a method like this:

@SuppressWarnings("unchecked")  // Safe. See below.
static <T> Optional<T> copyOf(Optional<? extends T> opt) {
  return (Optional<T>) opt;
}

(If you don't like the name copyOf, see my comment about Guava's ImmutableList below)

This is very efficient in terms of runtime speed: the cast gets elided at compile time:

static <T> java.util.Optional<T> copyOf(java.util.Optional<? extends T>);
    Code:
       0: aload_0  # Read the parameter.
       1: areturn  # Return the parameter.

so the only cost is that of a method call; this is easily done away with by the JIT.

You can then invoke like:

Optional<A> a = copyOf(func2());

This is safe because Optional has the following property: it is guaranteed not to have any state changes caused by setter methods taking parameters dependent upon the type variable T. Phew. Quite a mouthful. I'll make it more concrete.

Because Optional

  1. has no setter methods (of any kind, but more generally none that take parameters of type T, SomeGenericType<T> etc)
  2. is final (so you can't subclass it to add a setter to violate the previous point)

there is nothing you can do to the value held by the Optional<T> (or lack thereof) that will make it not an instance of T (or lack thereof).

And because every instance of T is also an instance of its superclasses, there is nothing unsafe about:

SuperclassOfT s = optionalOfT.get();

As such, this method is type safe (it will fail if you've invoked it on a non-present optional; but that's not a type error).

You will find similar code in Guava's ImmutableList.copyOf (the inspiration for calling it "copyOf" above, even though it's not really a copy). There, there are setter methods (like add), but those methods immediately throw UnsupportedOperationExceptions, and thus do not affect the list's state.


Note that whilst immutable types have the necessary properties described above to make such a cast safe, the type does not necessarily need to be immutable to perform the cast safely.

For example, you could have an ErasableOptional<T> type, which has an erase() method on it which, when called, converted a "present" value into an "absent" value (i.e. get() no longer succeeds). It would be safe to cast such an instance to an ErasableOptional<SupertypeOfT> because the value is either a T or absent; you can't make it not an instance of SupertypeOfT or absent.


Optional is, quote from java doc:

a container object which may or may not contain a non-null value.... Additional methods that depend on the presence or absence of a contained, such as orElse() ...

As we can see Optional container, uses generic type to define which object to contain.

Optional <T>

so you can do this:

Optional<? extends A> a = func2(); // 2. Upcasting Will work :)

and to access the optional object a an object of type A :

a.get();