Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 446
hammerfest Avatar asked Dec 01 '25 22:12

hammerfest


2 Answers

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);
}
like image 71
LuCio Avatar answered Dec 04 '25 11:12

LuCio


Shouldn't you be able to say something like:

.map(x -> new SimpleEntry<>(this.getFieldOne(x), this.getFieldTwo(x)))
.filter(e -> evaluateTheCondition(e.getKey()))
.map(Entry::getValue)
.ifPresent(builder::withFieldTwo);
like image 34
Eugene Avatar answered Dec 04 '25 10:12

Eugene