Code Review · Java
Java Code Review: NullPointerException Risk
Review Java code that assumes inputs and object fields are never null.
Code Review Exercise
Review the following Java code. The method looks simple, but it has several reliability and maintainability issues.
public class OrderService {
public boolean shouldApplyDiscount(Order order) {
return order.getCustomer().getStatus().equals("VIP")
&& order.getTotalAmount() > 100;
}
}What issues do you see before scrolling further?
Review Findings
Issue #1: Chained calls can throw NullPointerException
Any part of this chain can be null: order, getCustomer(), or getStatus(). If one of them is null, the method throws instead of returning a safe answer.'
Issue #2: equals() is called on a possibly null value
order.getCustomer().getStatus().equals("VIP") will fail if getStatus() returns null. A constant-first comparison is safer: "VIP".equals(status).
Issue #3: Magic string
"VIP" is a business value hidden as a raw string. If customer status is important to the domain, an enum or constant would make the code safer and easier to refactor.
Issue #4: Business logic is hard to read
The method mixes null navigation, status comparison, and amount logic in one expression. Breaking it into named steps makes the intent easier to review.
Why This Is Easy To Miss
The code reads nicely from left to right, which makes it feel clean. But chained method calls hide risk. In code review, a good habit is to ask: which values are guaranteed to be non-null?
Fixed Version: Guard Clauses
One simple fix is to validate each required object before using it. This makes the null behavior explicit.
public class OrderService {
private static final String VIP_STATUS = "VIP";
public boolean shouldApplyDiscount(Order order) {
if (order == null) return false;
if (order.getCustomer() == null) return false;
String status = order.getCustomer().getStatus();
return VIP_STATUS.equals(status)
&& order.getTotalAmount() > 100;
}
}This version is not fancy, but it is clear. In interviews, clear and correct is usually better than clever.
Better Domain Model: Use an Enum
If customer status is a known set of values, an enum is usually better than strings.
enum CustomerStatus {
REGULAR,
VIP,
BLOCKED
}
public class OrderService {
public boolean shouldApplyDiscount(Order order) {
if (order == null || order.getCustomer() == null) {
return false;
}
Customer customer = order.getCustomer();
return CustomerStatus.VIP == customer.getStatus()
&& order.getTotalAmount() > 100;
}
}Using == with enums is normal in Java because enum constants are single instances. This also avoids typo bugs like "VPI".
Should You Use Optional Here?
Optional can be useful as a return type, but it should not be used just to hide unclear object ownership or messy domain modeling.
In a code review, a strong answer is not simply: “use Optional.” A stronger answer is: “first clarify which fields are allowed to be null, then make that contract obvious in the code.”
What Interviewers Expect
- Catch the immediate correctness issue: possible
NullPointerException. - Mention safer equality:
"VIP".equals(status). - Suggest improving the domain model with an enum or constant.
- Explain the tradeoff: guard clauses are simple, explicit, and easy to review.
Interview Follow-Ups
Is every NullPointerException fixed by adding more null checks?
No. Sometimes the better fix is to enforce invariants earlier, validate input at the boundary, or improve the domain model so impossible states cannot be represented.
Why is constant-first equals safer?
Because the constant is never null. "VIP".equals(status) returns false when status is null, while status.equals("VIP") throws NullPointerException.
When is == okay in Java?
It is okay for primitives and enums. For most objects such as String, use equals() for logical equality.
What is the maintainability issue with long chained calls?
They hide assumptions. A future reader has to know whether every object in the chain is guaranteed to exist. Named local variables and guard clauses often make the code easier to understand.