java – Correct handling of null in large data nesting

Question:

Hello! For example, you need to load JSON from the server and display some fields in the UI. But sometimes, the nesting of data is very large and one object can contain a bunch of other nested objects, which in turn also contain the same nested objects. And there is a possibility that sometimes due to bugs on the server some fields may contain null.

If you write the logic for receiving and displaying data for a Java model based on JSON, then due to the large nesting of data, the code starts to get littered with checks for null, and if you need to hang additional logic for processing data, then everything becomes even more deplorable in terms of readability.

I created a small example (Invented) and tried to separate the logic for receiving data from the model and displaying it into separate methods. Can you please tell me if I am doing the right thing? Or it is necessary to throw exceptions if the data came, for example, invalid or the required object == null.

It is assumed that in real tasks, the Job model can contain much more data.

Thanks in advance for your help.

public class Main {
static class Job {
    private int id;
    private List<Shipment> shipments;
    private Driver driver;
    private Truck truck;

    /* Предположим, что тут конструктор, а так же геттеры и сеттеры */
}

static class Shipment {
    private int id;
    private String goods;
    private Address address;

    /* Предположим что тут конструктор, а так же геттеры и сеттеры */
}

static class Address {
    private int id;
    private String city;

    /* Предположим что тут конструктор, а так же геттеры и сеттеры */
}

static class Driver {
    private int id;
    private String firstName;
    private String lastName;

    /* Предположим что тут конструктор, а так же геттеры и сеттеры */
}

static class Truck {
    private int id;
    private String number;

    /* Предположим что тут конструктор, а так же геттеры и сеттеры */
}

public static void main(String[] args) {
    Job job = load();
    updateUI(job);
}

/**
 * Эмулирует заргузку модели Job
 * @return Job
 */
static Job load() {
    Driver driver = new Driver(1, "John", "Kristoff");
    Truck truck = new Truck(1, "NV157");
    Address address = new Address(1, "New York");
    Shipment shipment = new Shipment(1, "Coffee", address);

    List<Shipment> shipments = Collections.singletonList(shipment);
    return new Job(1, shipments, driver, truck);
}

static void updateUI(Job job) {
    if (job == null) {
        return;
    }

    showShipments(job.getShipments());
    showDriver(job.getDriver());
    showTruck(job.getTruck());
}

static void showShipments(List<Shipment> shipments) {
    if (shipments == null) {
        return;
    }

    for (Shipment shipment: shipments) {
        System.out.println("Goods in the shipment: " + shipment.getGoods());

        if (shipment.getAddress() != null) {
            System.out.println("Shipment`s address: " + shipment.getAddress().getCity());
        }
    }
}

static void showDriver(Driver driver) {
    if (driver == null) {
        return;
    }

    System.out.println("Driver`s first name: " + driver.getFirstName());
    System.out.println("Driver`s last name: " + driver.getLastName());
}

static void showTruck(Truck truck) {
    if (truck == null) {
        return;
    }

    System.out.println("Truck: " + truck.getNumber());
}

}

Answer:

Loading such a tree of objects into the UI is rather rash. Unnecessary connections need to be severed. It is enough for a Job object to have objects "reference" to Driver, Track:


public class Job {
    private int id;
    private ReferenceData driver;
    private ReferenceData truck;
}

public class ReferenceData {
    private int id;
    private String description;
}

The reference object helps you break complex objects into separate units. Especially when they are processed separately.

When processing a complete tree of objects, it is better to wrap the relationship in Optional. This approach avoids NullPointerException when handling:


static void showDriver(Optional&ltDriver> driver) {
    driver.foreach(d -> {
        System.out.println("Driver`s first name: " + d.getFirstName());
        System.out.println("Driver`s last name: " + d.getLastName());
    }
}

Scroll to Top
AllEscort