Java – map filter lambda expression using two fields from different class hierarchy routes
We have a method that receives class objects at the top of the class hierarchy It uses a condition based on a field deeper in the hierarchy. If it is met, it uses another field of the builder. It can also be deeper in the hierarchy, but on different paths from the top-level 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 hope it's best to condense it into a statement, as shown below
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 condition evaluation, it seems that we can't "go back" to topclass to map it to fieldtwo for the builder Is a statement feasible?
Solution
If you 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 requires fieldone as input in the filter, but to keep topclass in the current state of optional, we will not map to fieldone Instead, use the method getfieldone If the filter is passed, we can map topclass to the result of the builder applied on fieldtwo retrieved by the method getfieldtwo
Or use 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); }