0

I'm stuck trying to pass Optional.toJavaUtil() as method reference to a map method (either Optional.map() and Stream.map()).

The simplified example of my code:

aLegacyService.getGuavaOptional()
    .toJavaUtil()
    .map(MyPojo::getAnotherGuavaOptional)
    .flatMap(Optional::toJavaUtil);    // <-- This doesn't compile

The compiler gives me a cryptic error:

Error:(177, 72) java: invalid method reference
  non-static method toJavaUtil() cannot be referenced from a static context

I think the reason is that there are 2 methods: instance method and static method, both with the same name. If I use lambda syntax, both variants work fine:

.flatMap(opt -> opt.toJavaUtil())            // This is OK
// and
.flatMap(opt -> Optional.toJavaUtil(opt));   // Also OK

Q: Is there a way to make this work with method reference? (e.g. by somehow specifying which of two methods I want to use?)

Yoory N.
  • 4,881
  • 4
  • 23
  • 28
  • 7
    from the documentation --> _Unfortunately, the method reference Optional::toJavaUtil will not work, because it could refer to either the static or instance version of this method. Write out the lambda expression o -> Optional.toJavaUtil(o) instead._ – Ousmane D. Mar 01 '18 at 08:56
  • @Aominè, oh, where were my eyes? :) Thanks for pointing this out! – Yoory N. Mar 01 '18 at 08:58
  • Side-question: If both `aLegacyService` and `MyPojo` work with Guava Optional, wouldn't one combine the two directly and only convert to a Java Optional at the end? – Thilo Mar 01 '18 at 08:59
  • 1
    @Thilo There is no `flatMap` equivalent in Guava's Optional. I was at first trying to use Guava's `transform` method, but then I have to write my own equivalent to flatMap because I get `Optional>`. (Refactoring of that legacy service and its domain objects to use Java's Optional is not an option right now). – Yoory N. Mar 01 '18 at 09:04
  • 2
    That's an odd piece of API design. The only difference I can see is the "or null if the argument is null." aspect of the static method. This seems like a far more marginal use case than wanting to use a method reference. Perhaps @LouisWasserman could provide some context. – Andy Turner Mar 01 '18 at 09:06
  • No `flatMap` ("`transformAndConcat`") indeed... https://github.com/google/guava/issues/1450 :-( – Thilo Mar 01 '18 at 09:11
  • @AndyTurner to me, it not only looks like a marginal use case, the “or null if the argument is null” behavior contradicts the entire idea of using optional instead of `null`… – Holger Mar 01 '18 at 10:02
  • @Holger indeed. – Andy Turner Mar 01 '18 at 10:11
  • @AndyTurner @Holger The main idea, IIRC, of the static `Optional.toJavaUtil(Optional)` is that it can be used in automated replacements of Guava `Optional` with the JDK `Optional`; just stick that method call in as a conversion at places where a Guava `Optional` is passed in, and you get an exact equivalent, including getting `null` if the input is `null` (something which does, surprisingly, happen in some cases). – ColinD Mar 01 '18 at 18:03
  • 2
    @ColinD ok, but why make it an overload? Calling it e.g. `toNullableJavaUtil` would have avoided the name clash, as well as pointing to the fact there is something fishy going on with the potentially-null optional. – Andy Turner Mar 01 '18 at 18:27
  • One bit of insight: assuming your class contains both Guava `Optional` and JDK `Optional`, you can only import one. Assuming you import the newer JDK `Optional` then the method reference has to be `com.google.common.base.Optional::toJavaUtil` which is a lot less pleasant than `o -> o.toJavaUtil()`. – dimo414 Feb 12 '19 at 04:45

0 Answers0