Null handling tests whether a reference or value is absent before accessing it. The check prevents runtime failures, but repeated checks can hide the business rule, duplicate expressions, and push more defensive work onto callers. section 1.2 section 1.3
From defensive plumbing to intent
A Java price lookup checks the product, pricing details, discounted price, and base price through nested conditionals, then returns null when no price exists. A Kotlin version expresses the intended rule directly: use the discounted amount, otherwise the base amount. For a user’s city, Java’s repeated checks become an Optional chain that supplies "Unknown" when any step is absent. section 1.2 section 1.1
Prefer null handling that makes absence explicit and keeps the main rule readable:
- Use a type-system representation of absence when the language provides one, such as Kotlin nullable types. section 1.2
- Replace duplicated conditional navigation with safe-call, mapping, or fallback operations when they preserve the intended behavior. section 1.2 section 1.1
- Do not treat a final null return as a complete design; it transfers defensive checks to every caller. section 1.2
Figure 1.2 A product may be missing entirely, lack pricing details, or have no discounted price. When pricing details exist, the base price is always present.
Use the state diagram to distinguish a missing product, missing pricing details, and missing discounted price from the guaranteed base price. section 1.2
Listing 1.1 Getting the final price of a product
public BigDecimal getFinalPrice(Product product) {
if (product != null #1
&& product.pricingDetails() != null) { #1
if (product.pricingDetails() #1
.discountedPrice() != null) { #1
return product.pricingDetails() #2
.discountedPrice().amount(); #2
} else if (product.pricingDetails() #3
.basePrice() != null) { #3
return product.pricingDetails() #4
.basePrice().amount(); #4
} #4
}
return null; #5
}
Inspect the verbose Java implementation to see how repeated null checks obscure the final-price rule. section 1.2
String city = Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.orElse("Unknown");
Compare the Optional chain with nested checks and follow how each absent value leads to the "Unknown" fallback. section 1.1

