# ofNullable<T> static method

Optional<T> ofNullable<T>(

1. T? value

)

Returns an Optional describing the given value, if non-null, otherwise returns an empty Optional.

`value` the possibly-null value to describe

Returns an Optional with a present value if the specified value is non-null, otherwise an empty Optional.

## Example

    String? nullableValue = "Hello";
    Optional<String> opt1 = Optional.ofNullable(nullableValue);
    print(opt1.isPresent()); // true

    nullableValue = null;
    Optional<String> opt2 = Optional.ofNullable(nullableValue);
    print(opt2.isEmpty()); // true

    // Useful for method parameters
    void processName(String? name) {
      Optional.ofNullable(name)
        .map((n) => n.toUpperCase())
        .ifPresent((n) => print("Processing: $n"));
    }

A container object which may or may not contain a non-null value.

If a value is present, isPresent returns `true`. If no value is present, the object is considered empty and isPresent returns `false`.

Additional methods that depend on the presence or absence of a contained value are provided, such as orElse (returns a default value if no value is present) and ifPresent (performs an action if a value is present).

## Usage Examples

### Basic Creation and Checking

    // Create an Optional with a value
    Optional<String> name = Optional.of("John");
    print(name.isPresent()); // true
    print(name.get()); // "John"

    // Create an empty Optional
    Optional<String> empty = Optional.empty();
    print(empty.isPresent()); // false
    print(empty.isEmpty()); // true

    // Create Optional from nullable value
    String? nullableValue = null;
    Optional<String> fromNullable = Optional.ofNullable(nullableValue);
    print(fromNullable.isEmpty()); // true

### Safe Value Retrieval

    Optional<String> name = Optional.of("Alice");
    Optional<String> empty = Optional.empty();

    // Using orElse for default values
    print(name.orElse("Unknown")); // "Alice"
    print(empty.orElse("Unknown")); // "Unknown"

    // Using orElseGet with a supplier function
    print(empty.orElseGet(() => "Generated default")); // "Generated default"

    // Using orElseThrow
    try {
      print(empty.orElseThrow(() => Exception("No value present")));
    } catch (e) {
      print("Caught: $e"); // Caught: Exception: No value present
    }

### Conditional Operations

    Optional<String> name = Optional.of("Bob");
    Optional<String> empty = Optional.empty();

    // Execute action if value is present
    name.ifPresent((value) => print("Hello, $value!")); // Hello, Bob!
    empty.ifPresent((value) => print("This won't print"));

    // Execute different actions based on presence
    name.ifPresentOrElse(
      (value) => print("Found: $value"), // This executes
      () => print("No value found")
    );

    empty.ifPresentOrElse(
      (value) => print("Found: $value"),
      () => print("No value found") // This executes
    );

### Transformations and Filtering

    Optional<String> name = Optional.of("john doe");

    // Transform the value if present
    Optional<String> upperName = name.map((s) => s.toUpperCase());
    print(upperName.get()); // "JOHN DOE"

    // Chain transformations
    Optional<int> nameLength = name
        .map((s) => s.replaceAll(" ", ""))
        .map((s) => s.length);
    print(nameLength.get()); // 7

    // Filter based on condition
    Optional<String> longName = name.filter((s) => s.length > 5);
    print(longName.isPresent()); // true

    Optional<String> shortName = name.filter((s) => s.length < 5);
    print(shortName.isEmpty()); // true

    // FlatMap for nested Optionals
    Optional<String> parseNumber(String s) {
      try {
        int.parse(s);
        return Optional.of(s);
      } catch (e) {
        return Optional.empty();
      }
    }

    Optional<String> input = Optional.of("123");
    Optional<String> validNumber = input.flatMap(parseNumber);
    print(validNumber.isPresent()); // true

### Working with Collections

    List<Optional<String>> optionals = [
      Optional.of("apple"),
      Optional.empty(),
      Optional.of("banana"),
      Optional.empty(),
      Optional.of("cherry")
    ];

    // Filter out empty optionals and get values
    List<String> fruits = optionals
        .where((opt) => opt.isPresent())
        .map((opt) => opt.get())
        .toList();
    print(fruits); // [apple, banana, cherry]

    // Using stream() method for functional processing
    List<String> upperFruits = optionals
        .expand((opt) => opt.stream())
        .map((fruit) => fruit.toUpperCase())
        .toList();
    print(upperFruits); // [APPLE, BANANA, CHERRY]

### Error Handling Patterns

    // Safe division function
    Optional<double> safeDivide(double a, double b) {
      return b != 0 ? Optional.of(a / b) : Optional.empty();
    }

    // Usage with error handling
    Optional<double> result = safeDivide(10, 2);
    result.ifPresentOrElse(
      (value) => print("Result: $value"), // Result: 5.0
      () => print("Division by zero!")
    );

    // Chain operations safely
    Optional<String> formatResult = safeDivide(15, 3)
        .filter((value) => value > 1)
        .map((value) => "Result: ${value.toStringAsFixed(2)}");

    print(formatResult.orElse("No valid result")); // Result: 5.00

## API Note

Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using `null` is likely to cause errors. A variable whose type is Optional should never itself be `null`; it should always point to an Optional instance.

## Implementation

    static Optional<T> ofNullable<T>(T? value) {
      return value == null ? empty<T>() : Optional<T>._(value);
    }