Kevin Jackson Kevin Jackson - 1 year ago 86
Java Question

Single-iteration over hierarchy in Java 8 (Solved)

How can I implement single-loop iteration over a hierarchy of different objects?

(I have used for-loops but these represent a different areas of a grid -- I can barely follow all the values used for positioning. Using a single loop would drastically simplify things.)

This hierarchy of objects is what I have....

class Hierarchical < PT extends Hierarchical<?,?,?>,T,CT extends Hierarchical< ?, ?, ? >>{
ObservableList< Hierarchical > children; //Zero or more objects..

class Seed extends Hierarchical { /* never has children-objects */ }
class Tree extends Hierarchical { ... }
class Planet extends Hierarchical { ... }

Edit: Children in the Planet instance are Trees, same for Trees containing Seeds.

...and this is what I want to do:

Planet p = new Planet(); //trees/seeds are instantiated internally.
Iterator< ? > itr = p.getChildren().iterator();
while ( itr.hasNext() ) {
Object obj =;
if ( obj instanceof Planet ){ /* cast to Planet & do stuff */ }
if ( obj instanceof Tree ){ /* cast to Tree & do stuff */ }
if ( obj instanceof Seed ){ /* cast to Seed & do stuff */ }

Clearly the answer lies in
Iterator< ? > itr = p.getChildren().iterator();
but how can it be implemented? It would seem that every level of the hierarchy would need to keep a position of it's children in the event its children start looping through their children. It's been far too long, I'm not familiar with design-patterns & java's collections anymore. :(

I'll note that I had an error when trying to use
Iterator< Hierarchical > itr = p.getChildren().iterator();
because p is of type Planet.

Edit: This needs to be "Depth-Last" (...or FIFO?). The looping is to simplify generation of the UI so the order is important.

== [SOLVED] =======================

Looking at it, I think I would want a custom iterator. But this works perfectly.

Credit goes to Ramsay Domloge. This is my implementation of his solution:

//..inside a function that is generating the UI...

class classGenerateRow implements Callback< DbObjectHierarchical< ?,?,? >, Object> {

GridPane pane;
int rowIndex;
int rowIndex_BeginVars;

ObservableList listVars = FXCollections.observableArrayList();

public classGenerateRow( GridPane pane, int rowIndex ){
this.pane = pane;
this.rowIndex = rowIndex;

public Object call( DbObjectHierarchical< ?,?,? > obj ){

//= QC SAMPLE ==============================
if ( obj instanceof QCSample ){

QCSample smp = (QCSample) obj;
int colIndex = colOffset_QCSample + (int) smp.getSampleNum() - 1;

if ( 1 == smp.getSampleNum() ) rowIndex_BeginVars = rowIndex; //store the starting-row for each Sample.
else rowIndex = rowIndex_BeginVars; //restart the index to the starting-row.

pane.add( new Label( "Sample "+smp.getSampleNum() ), colIndex, rowIndex );
listVars = smp.getChildren(); //NOTE: Assign listVars to match-up later with our grade requirements.

//= GRADE GROUP ============================
else if ( obj instanceof GradeGroup ){


GradeGroup grp = (GradeGroup) obj;
pane.add( new Label( grp.getLabel() ), colOffset_GradeGroup, rowIndex );

//= GRADE REQUIREMENT ======================
else if ( obj instanceof GradeRequirement ){


GradeRequirement req = (GradeRequirement) obj;
pane.add( new Label( req.getLabel() ), colOffset_GradeRequirement, rowIndex );

QCVariable obj_variable = QCVariable.fetchByRequirementId( req.getId(), listVars );
return null;

DbObjectHierarchical.visitAll( p, new classGenerateRow( pane, rowIndex ));

And the implementation...

//...inside the DbObjectHierarchical class...

* Starting with the provided object 'hierarchical', iterate down the hierarchy & running the Callback on each child before procedding deeper.
* Note, the provided object is excluded from being run through the Callback.
* @param hierarchical
* @param callback
@SuppressWarnings( { "rawtypes", "unchecked" } )
public static void visitAll( DbObjectHierarchical<?,?,?> hierarchical, Callback callback ){

Iterator < DbObjectHierarchical > itr_children = (Iterator< DbObjectHierarchical >) hierarchical.getChildren().iterator();

while ( itr_children.hasNext() ){

DbObjectHierarchical child =; child ); //render this objects UI before procedding to it's children.
DbObjectHierarchical.visitAll( child, callback );


I removed the LinkedList to maintain display order. Much like printing out a directory-tree that has mixed directories & files. The children (and children's children) are displayed as they are encountered, not 'all-first' or 'all-last'.

Thanks again. =)

Answer Source

If I have understood you right, you want to be able to visit every object in an object graph and do something with each object?

When each object implements a common interface, as yours do, this is simply resolved using recursion. Your only decision is whether you want to do depth-first recursion or breadth-first.

For depth first, you would want something like

public void visit(Hierarchical h) {
    // do something with h
    Iterator<Hierarchical> children = h.getChildren();
    while(children.hasNext()) {

It would seem that every level of the hierarchy would need to keep a position of it's children in the event its children start looping through their children

Using recursion in this way, you don't need to keep track of any 'position' - the state of the iterator is kept on the stack as you call the method again, so as the stack unwinds, when you get to a 'seed', you will roll back up the stack a level and call the next iteration of the iterator.

For breadth-first, you will need to process an entire node first, collecting branches as you go. When you have finished processing all children you need to start on the collection of branches.

public void visit(Hierarchical h) {
    List<Hierarchical> branches = new LinkedList<>();
    Iterator<Hierarchical> children = h.getChildren();

    while(children.hasNext()) {
        Hierarchical h =;
        // do something with h
        if(h.hasChildren()) {

    for(Hierarchical branch : branches) {
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download