1

I may be having it wrong but i am getting an error with an Optional<> as method argument in Java.

I have an interface:

public interface FooInterface;

And a class that implements it

public class Foo implements FooInterface;

Now, suppose i have a method that receives an Optional<FooInterface>

someMethod(Optional<FooInterface> arg)

I get an error if i do this:

Optional<Foo> foo = Optional.of(new Foo());
someMethod(foo);

It says that Optional<FooInterface> is expected instead of Optional<Foo>.

Why is that?

khelwood
  • 55,782
  • 14
  • 81
  • 108
user3013172
  • 1,637
  • 3
  • 15
  • 26
  • 3
    Try `someMethod(Optional extends FooInterface> arg)`. – Henrik Aasted Sørensen Jan 04 '18 at 15:06
  • 1
    See also [Why should Java 8's Optional not be used in arguments?](https://stackoverflow.com/questions/31922866/why-should-java-8s-optional-not-be-used-in-arguments) – khelwood Jan 04 '18 at 15:11
  • If possible modify `someMethod` method signature suggested by Henrik else try `Optional foo = Optional.of((FooInterface) new Foo());` – sanit Jan 04 '18 at 15:21

3 Answers3

1
  1. Use the interface type FooInterface:

    final FooInterface foo = new Foo();
    final Optional<FooInterface> optional = Optional.of(foo);
    
  2. Correct the argument type to Optional<? extends FooInterface>. It'll allow passing an Optional<AnyFooInterfaceSubclass>.

  3. Try not using the Optional for parameters and fields.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
1

That is a general drawback of generic types involving extends/implements.

interface Ifc { }
class Cls implements Ifc { }
void somemethod2(List<Ifc> arg) { }

List<Cls> list = new UnlinkedList<>();
somemethod2(list); // COMPILE ERROR

In your case a solution would be:

somemethod(Optional<FooInterface>.of(foo));

Or declare

void someMethod(Optional<? extends FooInterface> arg) {

Fortunately Optional is immutable, but for List this would be problematically, as you could not set an element with Foo, as it could have been a List of an other FooInterface implementing class. So maybe better to avoid.


There exist some proponents of avoiding Optional parameters, in favor of doing only work on non-optional objects. I do not see that as such. IMHO there are many valid uses of Optional parameters.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
0

This has nothing to do with Optional itself, it applies to any generic type.

Java generics are invariant, which means Collection<Foo> (or Optional, or whatever) is not a subtype of Collection<FooInterface>, even though Foo itself is a subtype of FooInterface.

You need to make that generic type covariant using a wildcard (as @Henrik pointed out already):

/**
 * accepts an optional value of type `FooInterface` or any subtype
 */
someMethod(Optional<? extends FooInterface> arg);    
Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92