Choose traversal style for Java composites deliberately, balancing recursion, explicit iterators, streams, and failure handling.
Composite almost always leads to traversal design questions.
For many Java composites, recursion keeps the code closest to the model:
1public Money total() {
2 return children.stream()
3 .map(PriceNode::total)
4 .reduce(Money.zero(), Money::add);
5}
That is often enough when:
Use explicit iteration when you need:
At that point, a dedicated iterator, visitor, or traversal service may be clearer than hiding everything inside one recursive method.
Ask what happens when traversal fails on one child:
Recursive elegance does not remove that design choice.
Keep traversal logic close to the model only while it remains understandable. If traversal rules start carrying policy, filtering, or complex failure handling, pull them into a dedicated collaborator.