I wonder whether there is a better way of handling nulls for deeply nested data?
Lets say i have 4 classes namely University, Branch, Student, Information nested one around other.
class University{
Branch branch;
//getters & setters
}
class Branch{
Student student;
//getters & setters
}
class Student{
Information information;
//getters & setters
}
class Information{
String name;
List<Boolean> attendance;
//getters & setters
}
For some reason, i want student Name to be consumed, for which we just navigate
university.getBranch().getStudent().getInformation().getName()
which is prone to raise null exceptions.
For that reason we always put an if block around it to check nulls,Something like this
if(university != null && university.getBranch() != null ..... )
Above the nested depth is 4, sometimes i have depth more than 8 or 9. In those situations, something like above doesn't make sense, we are rather sacrificing clean code.
I need a better approach for this problem
Below are few ways i found helpful with their own limitations:
- PropertySource.getNestedProperty() - Apache common beanUtils library, which almost worked for me except it throws
NestedNullExceptionwhich needs to be handled usingtry{}catch(){}which for some reason, we don't want to do. Even have issues when dealing with lists. - Optionals - Java 8 provides final Class Optional
*Traditional Way :*
if (university != null) {
Branch branch = user.getBranch();
if (branch != null) {
Student student = branch.getStudent();
if (student != null) {
Information info = student.getInformation();
if (info != null) {
name = info.getName();
}
}
}
}
*Java 8 Optionals :*
Optional<String> optional = Optional.ofNullable(user)
.flatMap(University::getBranch)
.flatMap(Branch::getStudent)
.map(Student::getInformation)
.orElse("default");
Code looks much clean now except we need to create an object for every Optional(if we want to use that optional more than once)
- The Third way of doing is JSONfying entire object using Object Mapper and get that data directly
responseEntityJson = objectMapper.writeValueAsString(responseEntity);
rootNode = objectMapper.readTree(responseEntityJson);
DataValue = rootNode.findValue("Data");
I'm looking forward to know your opinions.