Using two fields from different class hierarchy routes for map-filter lambda expression

hammerfest :

We have a method which receives an object of the class on the top of the class hierarchy. It uses a condition based on a field somewhere deeper in the hierarchy, and if that is fulfilled then it uses for a builder another field also somewhere deeper in the hierarchy but on a different route starting from the top class.

public Optional<SomeType> create(final TopClassInHierarchy topClass) {
  Optional<SomeType> someObject = Optional.empty();
  if (someCondition.evaluate(getFieldOne(topClass))) {
      someObject = Optional.of(new SomeType.Builder()
              .withFieldTwo(getFieldTwo(topClass))
              .build());
  }
  return someObject;

private FieldOne getFieldOne(TopClassInHierarchy topClass) { return topClass.getSomething()...getFieldOne();
private FieldTwo getFieldTwo(TopClassInHierarchy topClass) { return topClass.getSomethingElse()...getFieldTwo();

We would like to preferably condense this into one statement, something like this

SomeType.Builder builder = new SomeType.Builder();
Optional.of(topClass)
        .map(this::getFieldOne)
        .filter(someCondition::evaluate)
        .map(this::getFieldTwo) //???
        .ifPresent(builder::withFieldTwo);

However, once we map topClass down to fieldOne for the condition evaluation, afterwards we don't seem to be able to "step back" to topClass to map it down to fieldTwo for the builder. Is this feasible with one statement?

LuCio :

If think this should work:

public Optional<SomeType> create(final TopClassInHierarchy topClass) {
  Builder builder = new Builder();

  return Optional.of(topClass)
    .filter(tc -> someCondition.evaluate(getFieldOne(tc)))
    .map(tc -> builder.withFieldTwo(getFieldTwo(tc)).build());
}

someCondition.evaluate in filter needs fieldOne as input, but to keep topClass as the current state of the Optional we do not map to fieldOne. Instead the method getFieldOne is used. If the filter is passed we can map topClass to the result of the builder applied on fieldTwo retrieved by the method getFieldTwo.

Or with more intermediate mappings:

public Optional<SomeType> create(final TopClassInHierarchy topClass) {
    Builder builder = new Builder();

    return Optional.of(topClass)
            .filter(tc -> someCondition.evaluate(getFieldOne(tc)))
            .map(this::getFieldTwo)
            .map(builder::withFieldTwo)
            .map(Builder::build);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=88312&siteId=1