Contents

// 1. Empty Optional — holds no value Optional<String> empty = Optional.empty(); // 2. Non-null value — throws NullPointerException if value is null Optional<String> present = Optional.of("hello"); // 3. Nullable value — wraps null in an empty Optional instead of throwing Optional<String> nullable = Optional.ofNullable(null); // same as Optional.empty() Optional<String> nullable2 = Optional.ofNullable("world"); // same as Optional.of("world") Optional<String> opt = Optional.of("Java"); opt.isPresent(); // true — value is present opt.isEmpty(); // false — Java 11+ Optional<String> empty = Optional.empty(); empty.isPresent(); // false empty.isEmpty(); // true Optional<String> opt = Optional.ofNullable(getValue()); // may be null // get() — throws NoSuchElementException if empty; AVOID using directly String s1 = opt.get(); // orElse() — return default value if empty (default always evaluated) String s2 = opt.orElse("default"); // orElseGet() — return result of Supplier; lazy (only called if empty) String s3 = opt.orElseGet(() -> computeDefault()); // orElseThrow() — throw custom exception if empty String s4 = opt.orElseThrow(() -> new IllegalStateException("Value missing")); // ifPresent() — execute consumer only if value present opt.ifPresent(v -> System.out.println("Found: " + v)); // ifPresentOrElse() — Java 9+ opt.ifPresentOrElse( v -> System.out.println("Found: " + v), () -> System.out.println("Not found") ); Prefer orElseGet() over orElse() when the default involves an expensive computation or method call, because orElse() always evaluates its argument.

map() applies a function to the value if present and wraps the result in a new Optional. flatMap() is used when the mapping function itself returns an Optional, avoiding a nested Optional<Optional<T>>.

Optional<String> name = Optional.of(" alice "); // map — trim and uppercase Optional<String> upper = name.map(String::trim).map(String::toUpperCase); upper.ifPresent(System.out::println); // ALICE // Without Optional (old style — prone to NPE): String result = null; String raw = getName(); if (raw != null) { result = raw.trim().toUpperCase(); } // flatMap — when the mapper returns Optional itself class User { Optional<Address> getAddress() { return Optional.ofNullable(address); } } class Address { Optional<String> getCity() { return Optional.ofNullable(city); } } // flatMap avoids Optional<Optional<String>> Optional<String> city = getUser() .flatMap(User::getAddress) .flatMap(Address::getCity);

filter() takes a predicate. If the value is present and passes the predicate, it returns the same Optional; otherwise it returns an empty Optional.

Optional<Integer> age = Optional.of(25); Optional<Integer> adult = age.filter(a -> a >= 18); adult.isPresent(); // true Optional<Integer> minor = Optional.of(15).filter(a -> a >= 18); minor.isPresent(); // false — 15 < 18 so filter returns empty

A service method that looks up a user by ID and returns the user's email in uppercase:

public Optional<String> findUserEmailById(int id) { return userRepository.findById(id) // returns Optional<User> .filter(User::isActive) // keep only active users .map(User::getEmail) // Optional<String> .map(String::toUpperCase); // transform email } // Caller: String email = findUserEmailById(42) .orElse("unknown@example.com");
Optional adds a small object-allocation overhead. In performance-critical inner loops, plain null checks may be preferable.