7

I have the following:

class Foo implements Inter {
    void doSomething();
}

Optional<Inter> getPossible() {
    Optional<Foo> possible = ...;
    possible.ifPresent(Foo::doSomething);
    return possible.map(f -> f);
}

getPossible needs to return an Optional<Inter> because it's overriding a superclass's implementation.

That map at the end of the method is purely to convert the type. Is there a more elegant option?

xxxvodnikxxx
  • 1,270
  • 2
  • 18
  • 37
sprinter
  • 27,148
  • 6
  • 47
  • 78

3 Answers3

9

To make clear that you only need casting, you can use Class::cast with .map:

class Foo implements Inter {
    void doSomething();
}

Optional<Inter> getPossible() {
    Optional<Foo> possible = ...;
    possible.ifPresent(Foo::doSomething);
    return possible.map(Inter.class::cast);
}
Christian
  • 13,285
  • 2
  • 32
  • 49
  • The small downside of this approach is that it does unnecessary casting at runtime for a cast that will never fail. That said, casting should be pretty cheap these days. It also makes it seem like the casting is necessary (i.e. there may be a chance where it could fail), when it's just working around a compile-time limitation. Mapping using the identity instead of casting is just odd enough to call out that something weird is happening (or there's some redundant code that can be removed). – M. Justin Feb 15 '21 at 23:07
2

Return a Optional<? extends Inter> instead of an Optional<Inter>.

sprinter
  • 27,148
  • 6
  • 47
  • 78
  • 4
    If "getPossible needs to return an Optional because it's overriding a superclass's implementation" is true, changing the return type in a subclass to `Optional extends Inter>` shouldn't compile, unless you can also change the superclass – Chirlo Dec 04 '17 at 13:48
  • 4
    Besides that, having return types with wildcards is strongly discouraged. – Holger Dec 04 '17 at 15:06
  • @Holger appreciate an alternative then – sprinter Dec 04 '17 at 19:06
  • 1
    First of all, you should clarify why your solution works. As @Chirlo correctly pointed out, if the superclass declaration truly is `Optional getPossible()`, you can’t override it with a method having the signature `Optional extends Inter> getPossible()`. If that works, there must be an error in your premise, which would void your entire question. Once we know your true setup, we can suggest a solution. – Holger Dec 05 '17 at 09:07
1

One alternative would be to edit the method signature in Foo to become the following:

class Foo implements Inter {
    Inter doSomething() {
        ...
        return this;
    }
}

Now, you can simplify getPossible to the following:

Optional<Inter> getPossible() {
    Optional<Foo> possible = ...;
    return possible.map(Foo::doSomething);
}
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • Instead of changing the signature of `doSomething()`, you could resort to a lambda expression, `return possible.map(foo -> { foo.doSomething(); return foo; });` – Holger Dec 05 '17 at 09:15