Eliminating NullPointerExceptions in Method Chains
How to avoid NullPointerException in chained get calls? If you are looking for an answer to this question, you are in the right place.
If you want to have a reliable code base, the first thing you need to do is try to avoid NullPointerException and handle possible NullPointerExceptions gracefully. Sometimes this is difficult to do because avoiding NullPointerException can make your code base ugly, decrease the reliability of the code, etc.
In this article, I will mention the ways to avoid and handle possible NullPointerExceptions in chained method calls. I hope this article helps you to increase the code quality of your project.
Let's first identify the issue. When we have lots of nested objects and want to reach a specific value, we need to make many get calls to retrieve the value. Consider below example,
user.getUserDetails().getContactDetails().getPhoneNumbers().get(0);
When you have a similar nested structure like the above example, you need to chain many get calls to get the phone number of the user. But the problem is this code is vulnerable and can break the application because of NullPointerException. In this example, user
, userDetails
, contactDetails
, and phoneNumbers
can be null and cause a NullPointerException. You can use four different methods to avoid application crash that occurs because of NPE.
1. Make a Null Check for Every Object
Here two example way of doing it.
if(user != null &&
user.getUserDetails() != null &&
user.getUserDetails().getContactDetails() != null &&
user.getUserDetails().getContactDetails().getPhoneNumbers() != null &&
user.getUserDetails().getContactDetails().getPhoneNumbers().get(0) != null) {
user.getUserDetails().getContactDetails().getPhoneNumbers().get(0);
// use the phone number
}
if(user != null) {
var userDetails = user.getUserDetails();
if(userDetails != null) {
var contactDetails = user.getUserDetails().getContactDetails();
if(contactDetails != null) {
var phoneNumbers = user.getUserDetails().getContactDetails().getPhoneNumbers();
if(phoneNumbers != null) {
var phoneNumber = user.getUserDetails().getContactDetails().getPhoneNumbers().get(0);
if(phoneNumber != null) {
// use the phone number
}
}
}
}
}
Both of the above strategies are verbose and ugly code. It is hard to read also.
2. Wrap with Try-Catch Block and Catch the NPE
The second way of solving this issue is wrapping the statement with try-catch block and handling the NullPointerException.
try {
var phoneNumber = user.getUserDetails().getContactDetails().getPhoneNumbers().get(0);
// use the phone number
} catch (NullPointerException exp) {
// handle possible exception case
}
3. Wrap with Optional
You can wrap the main object with Optional and map the all values step by step to get the phoneNumber object.
Optional.ofNullable(user)
.map(user -> user.getUserDetails())
.map(userDetails -> userDetails.getContactDetails())
.map(contactDetails -> contactDetails.getPhoneNumbers())
.map(phoneNumbers -> phoneNumbers.get(0))
.orElse("Default Number");
Optional mapping prevents the NPE by checking the existence of the value at every step. But it again requires many lines of code and verbose code blocks.
4. Use Generic Method to Get the Value
This is the best way to minimize the required lines of code and centralize the NullPointerException handling. We can get the whole statement as a parameter of the method and process this statement in the generic method.
public static <T> Optional<T> optional(Supplier<T> statement) {
try {
T value = statement.get();
return Optional.of(value);
} catch (NullPointerException exp) {
LOG.warn("Generic method caught a statement : {} with NPE : ", statement, exp);
return Optional.empty();
}
}
With the Supplier parameter, we are able to retrieve the value from the statement. In case a null value exists in the chained calls, we can catch the exception and handle it properly. Sample usage of this generic method is like this.
optional(
() -> user.getUserDetails().getContactDetails().getPhoneNumbers().get(0)
).ifPresent(// do something with phone number)
There is a difference between this generic method and Optional.ofNullable(). If chained method calls have a null value, then Optional.ofNullable does not prevent throwing the exception. But this method provides an option to handle it. That’s why, I consider this generic method as the best way to prevent crashes that occur because of the NullPointerException.
Preventing NullPointerExceptions or handling them gracefully helps you to have stable applications and more predictable code bases. So it is important to consider possible cases that can cause an NPE and either avoid them or handle them before it crashes your application.
👏 Thank You for Reading!
👨💼 I appreciate your time and hope you found this story insightful. If you enjoyed it, don’t forget to show your appreciation by clapping 👏 for the hard work and subscribe
📰 Keep the Knowledge Flowing by Sharing the Article!
✍ Feel free to share your feedback or opinions about the story. Your input helps me improve and create more valuable content for you.
✌ Stay Connected! 🚀 For more engaging articles, make sure to follow me on social media:
🔍 Explore More! 📖 Dive into a treasure trove of knowledge at Codimis. There’s always more to learn, and we’re here to help you on your journey of discovery.