This will show you how to replace old null checks with Optional in real-world code for cleaner, safer, and more functional-style Java.

1. Before: Traditional Null Checks

public String getUserEmail(User user) {
  if (user != null) {
    if (user.getEmail() != null) {
      return user.getEmail().toLowerCase();
    }
  }
  return "no-reply@example.com";
}

Problems:

  • Verbose nested if checks
  • Easy to forget a null check → NullPointerException
  • Harder to read and maintain

After: Using Optional

import java.util.Optional;

public String getUserEmail(User user) {
  return Optional.ofNullable(user)         // Wrap user safely
          .map(User::getEmail)       // Extract email if present
          .map(String::toLowerCase)     // Transform if present
          .orElse("no-reply@example.com"); // Default if empty
}

Benefits:

  • No explicit null checks
  • Clear transformation pipeline
  • Default value handled in one place

2. Before: Returning null from Methods

public String findUsernameById(int id) {
  User user = database.findUser(id);
  if (user != null) {
    return user.getUsername();
  }
  return null;
}

Problem: Callers must remember to check for null.

After: Returning Optional

public Optional<String> findUsernameById(int id) {
  return Optional.ofNullable(database.findUser(id))
          .map(User::getUsername);
}

// Caller side
String username = findUsernameById(42)
          .orElse("Guest");

Benefits:

  • Forces caller to handle absence explicitly
  • Eliminates silent null propagation

3. Before: Complex Null Chains

if (order != null && order.getCustomer() != null &&
  order.getCustomer().getAddress() != null) {
  return order.getCustomer().getAddress().getCity();
}
return "Unknown City";

After: Optional Chaining

return Optional.ofNullable(order)
        .map(Order::getCustomer)
        .map(Customer::getAddress)
        .map(Address::getCity)
        .orElse("Unknown City");

Benefits:

  • No deep nesting
  • Easy to extend or modify
  • Reads like a data pipeline

Pro Tips for Refactoring

✅ Start small — replace null checks in utility/helper methods first.

✅ Return Optional from methods that may not find a value.

✅ Don’t use Optional for:

  • Class fields (adds unnecessary wrapping)
  • Method parameters (confusing API design)
  • ✅ Prefer map + filter + flatMap over isPresent() + get().

Quick Conversion Pattern

▲Old Null-Check > Optional Equivalen

if (obj != null) obj.method() > Optional.ofNullable(obj).ifPresent(o -> o.method())
obj != null ? obj.value() : default > Optional.ofNullable(obj).map(o -> o.value()).orElse(default)
return obj == null ? null : obj.value() > return Optional.ofNullable(obj).map(o -> o.value())




← Back to Learning Journey