Java – what is the best way to navigate complex trees of different objects?
For example:
class Vehicle { Collection<Axle> axles; } class Axle { Collection<Wheel> wheels; } class Wheel { // I think there are dually rims that take two tires -- just go with it Collection<Tire> tires; } class Tire { int width; int diameter; }
I have a service through which I can get a collection of all vehicle objects I know Now that I have a tire of a specific width and diameter, I want to find a vehicle that can accept it The simple approach is to have a set of four nested loops, as follows:
for (Vehicle vehicle : vehicles) { for (Axle axle : vehicle.getAxles()) { for (Wheel wheel : axle.getWheels()) { for (Tire tire : wheel.getTires()) { if (tire.width == targetWidth && tire.diameter == targetDiameter) { // do something break; } } } } }
Is there a good design pattern? Or do you want to use a better data structure? Would it be better to keep an index in the location mapped to the tire information of the vehicle?
Editor: answer questions in comments
yes
yes
Not special
Sometimes it's just a vehicle, sometimes it's just an axle – two different environments
Yes, when I need the shaft
Edit2: further expand metaphor to explain the above two situations:
Background 1 – I want to know the vehicle, so I can send a worker to collect the vehicle and bring it back
Background 2 – I want to know the axles and tires because I'm trying to do this for the vehicle
Solution
You can use Java 8 streams to flatten loops
vehicles.stream() .flatMap(vehicle -> vehicle.getAxles().stream()) .flatMap(axle -> axle.getWheels().stream()) .flatMap(wheel -> wheel.getTires().stream()) .filter(tire -> tire.width == targetWidth && tire.diameter == targetDiameter) .forEach(tire -> { // do something });
The advantage of streaming is that you can insert additional filters, filters, findany, etc. anywhere in the sequence