Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guava Optional type, when transformation returns another Optional

I have a method that procudes an Optional<String>

But this String must be parsed at another application level as Integer or Long.

This I have a Function<String, Integer> that can be applied on the String, to produce an Integer. This transformation can fail because the String may not be an Integer parsable value.


I would like to return Optional when the transformation fails, instead of throwing a parsing exception.

I can't make the STRING_TO_INTEGER_FUNCTION return null, because it is not allowed by Guava:

Exception in thread "main" java.lang.NullPointerException: Transformation function cannot return null.

Thus the only thing I can do is having a Function<String,Optional<Integer>> but then I get as final result an Optional<Optional<Integer>> which isn't really cool because I may have another transformations to apply on it.


Does someone know how can I do something like that in Guava?

Optional.of("Toto").transform(STRING_TO_INTEGER_FUNCTION) = // Optional<Integer> ?

Thanks

like image 704
Sebastien Lorber Avatar asked Oct 25 '12 14:10

Sebastien Lorber


3 Answers

I guess you can do:

public static void main(final String[] args) {
  final Optional<Integer> valid = Optional.of("42")
      .transform(STR_TO_INT_FUNCTION)
      .or(Optional.<Integer>absent());
  System.out.println(valid); // Optional.of(42)
  final Optional<Integer> invalid = Optional.of("Toto")
      .transform(STR_TO_INT_FUNCTION)
      .or(Optional.<Integer>absent());
  System.out.println(invalid); // Optional.absent()
  final Optional<Integer> absent = Optional.<String>absent()
      .transform(STR_TO_INT_FUNCTION)
      .or(Optional.<Integer>absent());
  System.out.println(absent); // Optional.absent()
}

private static final Function<String, Optional<Integer>> STR_TO_INT_FUNCTION =
    new Function<String, Optional<Integer>>() {
      @Override
      public Optional<Integer> apply(final String input) {
        return Optional.fromNullable(Ints.tryParse(input));
      }
    };

Usage isn't that clumsy when you use Optional -> transform -> or in one line (assigning transformed optional integer would produce Optional<Optional<Integer>>).

like image 125
Xaerxess Avatar answered Nov 15 '22 03:11

Xaerxess


Using Optional.transform just doesn't seem compatible with a transformation that might fail - theoretically this implies an optional optional, when what you want to do is consolidate absences. I would recommend using something like the following:

Optional<String> strOptional = Optional.of("Toto");
Optional<Integer> intOptional =
        strOptional.isPresent()
        ? Optional.fromNullable(Ints.tryParse(strOptional.get()))
        : Optional.<Integer>absent();
like image 44
Paul Bellora Avatar answered Nov 15 '22 03:11

Paul Bellora


Another options except those stated above:

  • use plain old if/else (Guava team recommends not to overuse such constructs, it's often wise to obey these recommendation - otherwise you won't spare much lines of code and make readability worse)
  • use dirty trick: from(singleton("Toto")).transform(STRING_TO_INTEGER_FUNCTION).filter(notNull()).first().orNull() - only hypothetical idea, IMHO its badly readable too. At least it contains none generics, ?: operator or anonymous class, at the cost of more static imports.
  • wait for Java 8, where Optional.map allows null transformation result

You can vote for http://code.google.com/p/guava-libraries/issues/detail?id=1171 . Unfortunately Guava team seems hesitant with shifting this issue to some result.

like image 34
Tomáš Záluský Avatar answered Nov 15 '22 03:11

Tomáš Záluský