empty<T> static method

Optional<T> empty<T>()

Returns an empty Optional instance. No value is present for this Optional.

API Note

Though it may be tempting to do so, avoid testing if an object is empty by comparing with == against instances returned by Optional.empty. There is no guarantee that it is a singleton. Instead, use isEmpty or isPresent.

Example

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

// Don't do this - unreliable
// if (someOptional == Optional.empty()) { ... }

// Do this instead
if (someOptional.isEmpty()) { ... }

Returns an empty Optional.

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> empty<T>() => Optional<T>._(null);