flatMap<U> method

Optional<U> flatMap<U>([
  1. Optional<U> mapper(
    1. T
    )?
])

If a value is present, returns the result of applying the given Optional-bearing mapping function to the value, otherwise returns an empty Optional.

This method is similar to map, but the mapping function is one whose result is already an Optional, and if invoked, flatMap does not wrap it within an additional Optional.

mapper the mapping function to apply to a value, if present

Returns the result of applying an Optional-bearing mapping function to the value of this Optional, if a value is present, otherwise an empty Optional.

Throws InvalidArgumentException if the mapping function is null or returns null.

Example

// Helper function that returns Optional
Optional<int> parseInteger(String s) {
  try {
    return Optional.of(int.parse(s));
  } catch (e) {
    return Optional.empty();
  }
}

Optional<String> input = Optional.of("123");
Optional<String> empty = Optional.empty();

// Using flatMap to avoid nested Optionals
Optional<int> number = input.flatMap(parseInteger);
print(number.get()); // 123

// Compare with map (would create Optional<Optional<int>>)
// Optional<Optional<int>> nested = input.map(parseInteger);

// Empty input results in empty output
Optional<int> noNumber = empty.flatMap(parseInteger);
print(noNumber.isEmpty()); // true

// Chain multiple flatMap operations
Optional<String> result = Optional.of("42")
    .flatMap(parseInteger)
    .filter((n) => n > 0)
    .map((n) => "Number: $n");
print(result.get()); // "Number: 42"

// Real-world example: safe navigation
class Person {
  final String name;
  final Address? address;
  Person(this.name, this.address);
}

class Address {
  final String street;
  final String? zipCode;
  Address(this.street, this.zipCode);
}

Optional<String> getZipCode(Optional<Person> person) {
  return person
      .flatMap((p) => Optional.ofNullable(p.address))
      .flatMap((a) => Optional.ofNullable(a.zipCode));
}

Implementation

Optional<U> flatMap<U>([Optional<U> Function(T)? mapper]) {
  if (mapper == null) {
    throw InvalidArgumentException('mapper cannot be null');
  }
  if (isEmpty()) {
    return empty<U>();
  } else {
    Optional<U> result = mapper(_value as T);
    if (result.isEmpty()) {
      throw InvalidArgumentException('mapper returned null');
    }

    return result;
  }
}