I found a more Java8-ish solution with the smell of functional programming.
Given your six entities (note that I set Id for e6 , otherwise we get a NullPointerException ):
Entity e1 = new Entity(); e1.setId(400); Entity e2 = new Entity(); e2.setId(300); e2.setParentId(400); Entity e3 = new Entity(); e3.setId(200); e3.setParentId(300); Entity e4 = new Entity(); e4.setId(100); e4.setParentId(200); Entity e5 = new Entity(); e5.setId(50); e5.setParentId(100); Entity e6 = new Entity(); e6.setId(25); // this Id must be set, or we'll get a NPE e6.setParentId(50);
And a list containing them:
List<Entity> list = new ArrayList<>(); list.add(e1); list.add(e2); list.add(e3); list.add(e4); list.add(e5); list.add(e6);
Then for the parent hierarchy:
Function<Integer, Entity> byId = id -> list.stream() .filter(e -> e.getId().equals(id)) .findFirst() .orElse(null); Entity parentsSeed = byId.apply(100);
And for the hierarchy of children:
Entity childrenSeed = byId.apply(100); // e4 Function<Integer, Entity> byParentId = id -> list.stream() .filter(e -> id.equals(e.getParentId())) .findFirst() .orElse(null); UnaryOperator<Entity> nextChild = e -> e == null ? e : byParentId.apply(e.getId()); List<Entity> children = Stream.iterate(childrenSeed, nextChild) .limit(list.size()) .filter(Objects::nonNull) .collect(Collectors.toList()); // [e4, e5, e6]
The idea is to use the Stream.iterate() method by creating a stream using "functional" iteration.
For parents, I created a UnaryOperator (function), which when set to Entity returns either its parent Entity or null ; for children, I created UnaryOperator , which, with the Entity UnaryOperator , returns either its child Entity or null .
To perform these two searches, I used another Function that just looks for list on id and parentId respectively.