How to upcast object contained in Java 8 Optional?

Vatsal :

Is there an efficient way to perform upcasting while using an Optional object. Here is a sample code:

class A{}
class B extends A{}

B func(){
    //do something
    return new B();
}

Optional<B> func2(){
    //do something
    return Optional.of(new B());
}

main() {
    A a = func(); // Upcasting works fine
    B b = func(); // Upcasting works fine
    Optional<B> b = func2(); // 1. Works fine
    Optional<A> a = func2(); // 2. How to make this work ?
}

(2.) gives an error. I can solve it by creating another function.

But is there an efficient way, so that func2() can be used for both (1.) and (2.) ?

Andy Turner :

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.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=444741&siteId=1