🎓 A1Learner
🔍
0 of 30 lessons completed

Java Optional in Depth

Optional discipline is a set of habits for handling a missing value in the open. flatMap, orElseThrow and ifPresentOrElse give each missing-value case its own clear handling.

flatMap keeps the chain flat

A city lookup returns an Optional, and a country lookup takes a city and returns an Optional too. flatMap merges those two layers into one Optional of a country name.

import java.util.Optional;

public class Main {
  static Optional<String> findCity(String name) {
    if (name.equals("Ana")) {
      return Optional.of("Lisbon");
    }
    return Optional.empty();
  }

  static Optional<String> findCountry(String city) {
    if (city.equals("Lisbon")) {
      return Optional.of("Portugal");
    }
    return Optional.empty();
  }

  public static void main(String[] args) {
    Optional<String> country = findCity("Ana")
        .flatMap(city -> findCountry(city));
    System.out.println(country.orElse("unknown"));
  }
}

orElseThrow names the failure

orElseThrow raises an exception when the Optional is empty. The catch block prints the message the program chose for that failure.

import java.util.Optional;

public class Main {
  static Optional<String> findCity(String name) {
    if (name.equals("Ana")) {
      return Optional.of("Lisbon");
    }
    return Optional.empty();
  }

  public static void main(String[] args) {
    try {
      String city = findCity("Ravi")
          .orElseThrow(() -> new IllegalStateException("No city on file for Ravi"));
      System.out.println(city);
    } catch (IllegalStateException e) {
      System.out.println(e.getMessage());
    }
  }
}

ifPresentOrElse on the present path

ifPresentOrElse takes two actions and picks one of them. A present value runs the first action with that value.

import java.util.Optional;

public class Main {
  static Optional<String> findCity(String name) {
    if (name.equals("Ana")) {
      return Optional.of("Lisbon");
    }
    return Optional.empty();
  }

  public static void main(String[] args) {
    findCity("Ana").ifPresentOrElse(
        city -> System.out.println("City: " + city),
        () -> System.out.println("No city on file"));
  }
}

ifPresentOrElse on the empty path

The same call shape handles the empty case in the same place. An empty Optional runs the second action instead.

import java.util.Optional;

public class Main {
  static Optional<String> findCity(String name) {
    if (name.equals("Ana")) {
      return Optional.of("Lisbon");
    }
    return Optional.empty();
  }

  public static void main(String[] args) {
    findCity("Ravi").ifPresentOrElse(
        city -> System.out.println("City: " + city),
        () -> System.out.println("No city on file"));
  }
}

Example

import java.util.Optional;

public class Main {
  static Optional<String> findCity(String name) {
    if (name.equals("Ben")) {
      return Optional.of("Porto");
    }
    return Optional.empty();
  }

  static Optional<String> findCountry(String city) {
    if (city.equals("Porto")) {
      return Optional.of("Portugal");
    }
    return Optional.empty();
  }

  public static void main(String[] args) {
    Optional<String> country = findCity("Ben")
        .flatMap(city -> findCountry(city));
    System.out.println(country.orElse("unknown"));
    try {
      String city = findCity("Zara")
          .orElseThrow(() -> new IllegalStateException("No city on file for Zara"));
      System.out.println(city);
    } catch (IllegalStateException e) {
      System.out.println(e.getMessage());
    }
    findCity("Ben").ifPresentOrElse(
        city -> System.out.println("City: " + city),
        () -> System.out.println("No city on file"));
  }
}

Key points

  • Use flatMap when the next step already returns an Optional, so the result stays one level deep.
  • Never call get() on an unchecked Optional, because an empty Optional has no value to give.
  • Optional works as a return type, not as a field or a parameter.
  • orElseThrow turns a missing value into an exception with a message the program chooses.
  • ifPresentOrElse runs one action for a present value and a different action for an empty one.
  • Optional discipline handles the missing case in code, rather than hiding it behind a null check far away.

In this example, one program uses all three tools on the same pair of lookups. flatMap prints a country value, orElseThrow prints its own message for a missing city, and ifPresentOrElse prints the present path for a found city.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A step in a lookup chain already returns an Optional. Which method keeps the result as one Optional instead of an Optional inside an Optional?