The first obvious way is to stream your items, filter them according to the necessary criteria, and then apply the action to each remaining item. It also makes the code much cleaner:
List<Outer> outers = getOutersFromSomewhere(); outers.stream().filter(Outer::isImportant) .forEach(outer -> doImportantAction(outer, outerDate)); outers.stream().filter(Outer::isTrivial) .forEach(outer -> doTrivialAction(outer, outerDate));
Caution: This only works if important, trivial, and standard elements form a partition. Otherwise, this is not equivalent to your if-else structure. But maybe it's all the same ...
The main problem with this approach: it is not a very good OOP. You request objects to make a decision. But OOP should βtell, don't askβ as much as possible.
So, another solution is to provide a consumption method in your Outer class:
public class Outer { ... public void act(OuterData data, Consumer<Outer> importantAction, Consumer<Outer> trivialAction, Consumer<Outer> defaultAction) { if (isImportant()) importantAction.accept(this, data); else if (isTrivial()) trivialAction.accept(this, data); else defaultAction.accept(this, data); } }
Now you call it that simple:
List<Outer> outers = getOutersFromSomewhere(); outers.forEach(outer -> outer.act(...));
This has a clear advantage: if you ever need to add a function to the Outer class - say, isComplex() - you only need to change the internals of this single class (and possibly allow the compiler to fail in other parts). Or maye you can add this function in a backward compatible way.
The same rules can apply to the Inner class and iteration.