# 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;
      }
    }