Ram
Ram

Reputation: 937

Graceful alternative to nested Optional.map?

I have multiple Optionals that must be mapped to a POJO. Is there a better alternative than the following?

class SimplePojo {
    private String stringField;
    private Integer integerField;
    // All args. constructor, getter, setter
}

Optional<String> stringOptional = ...
Optional<Integer> integerOptional = ...
Optional<SimplePojo> simplePojoOptional = stringOptional.flatMap(
    string -> integerOptional.map(integer -> new SimplePojo(string, integer)))

I have reduced the problem to 2 Optionals in the above example to keep it short. But I actually have 3 Optionals with more on the way. I am afraid the last line can easily become unwieldy soon.

Please note: Use of functional frameworks like Vavr or Functional Java is not an option for me.

Upvotes: 1

Views: 677

Answers (2)

Amad&#225;n
Amad&#225;n

Reputation: 748

I do not see any advantage from pursuing the functional style this way here. see three options:

ONE: If you can alter the SimplePojo class and if this scenario is a common one, you might consider to add a factory method to the SimplePojo:

class SimplePojo {
  public static Optional<SimplePojo> of(final Optional<String> stringField, final Optional<Integer> integerField) {
    if (stringField.isPresent() && integerField.isPresent()) {
      return new SimplePojo(stringField.get(), integerField.get());
    else
      return Optional.empty();
  }
}

TWO: If you cannot alter the SimplePojo, you might want to create this as a utility method somewhere else. If you need this pattern only in one class, make the method private in this class!

THREE: If you need to do this only once or twice, I would prefer the if...then construction from the first option over the functional notation you used for the sake of readability:

final Optional<SimplePojo> simplePojoOptional;
if (stringField.isPresent() && integerField.isPresent()) {
  simplePojoOptional = new SimplePojo(stringField.get(), integerField.get());
else
  simplePojoOptional = Optional.empty();

Upvotes: 1

iluxa
iluxa

Reputation: 6969

How about using a Builder ?

class SimplePojo {

  public static class Builder {
    private String stringField;

    public Builder withStringField(String str) {
      this.stringField = str;
      return this;
    }
    // and other "with" methods...


    public Optional<SimplePojo> build() {
      if (stringField == null || anotherField == null /* and so forth */) {
        return Optional.empty();
      } else {
        return Optional.of(new SimplePojo(this));
      }
    }
  }
  private final String stringField;

  /* private constructor, so client code has to go through the Builder */
  private SimplePojo(Builder builder) {
    this.stringField = builder.stringField;
    // etc.
  }
}

Then you could use it as follows:

SimplePojo.Builder builder = new SimplePojo.builder();
optionalStringField.ifPresent(builder::withStringField);
// etc.
return builder.build();

Upvotes: 1

Related Questions