Optional
java.util.Optional<T> — контейнер, который может содержать значение или
быть пустым. Это явный способ сказать «значение может отсутствовать», не прибегая
к null. Optional особенно полезен как возвращаемое значение методов,
которые «иногда не находят» результат: поиск в коллекции, чтение настроек,
парсинг.
Идея простая: вместо того чтобы возвращать null и заставлять вызывающий код
помнить про проверку, метод возвращает Optional. Тогда компилятор и API
сами «подталкивают» программиста обработать оба случая.
Основные методы
Optional.of(value) // value != null, иначе NPE
Optional.ofNullable(value) // допускает null -> empty
Optional.empty()
isPresent() / isEmpty()
get() // выбрасывает NoSuchElementException, если пусто
ifPresent(Consumer)
orElse(other)
orElseGet(Supplier)
orElseThrow(SupplierOfException)
map(Function) // преобразование, если значение есть
flatMap(Function) // если функция сама возвращает Optional
filter(Predicate)
Примеры
Пример 1. Создание Optional
import java.util.Optional;
public class OptionalCreate {
public static void main(String[] args) {
Optional<String> a = Optional.of("Робот");
Optional<String> b = Optional.ofNullable(null);
Optional<String> c = Optional.empty();
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
Output:
Optional[Робот]
Optional.empty
Optional.empty
Пример 2. ifPresent и orElse
import java.util.Optional;
public class OptionalIfPresent {
public static void main(String[] args) {
Optional<String> name = Optional.of("Phobo");
name.ifPresent(n -> System.out.println("Имя: " + n));
Optional<String> missing = Optional.empty();
String fallback = missing.orElse("неизвестно");
System.out.println("Значение: " + fallback);
}
}
Output:
Имя: Phobo
Значение: неизвестно
Пример 3. map и filter
import java.util.Optional;
public class OptionalMap {
public static void main(String[] args) {
Optional<String> raw = Optional.of(" 25 ");
int distance = raw.map(String::trim)
.map(Integer::parseInt)
.filter(d -> d > 0)
.orElse(-1);
System.out.println("Расстояние: " + distance);
int bad = Optional.<String>empty()
.map(Integer::parseInt)
.orElse(-1);
System.out.println("Из пустого: " + bad);
}
}
Output:
Расстояние: 25
Из пустого: -1
Пример 4. orElseThrow
import java.util.Optional;
public class OptionalThrow {
static String configValue(String key) {
return null; // имитация отсутствия
}
public static void main(String[] args) {
try {
String value = Optional.ofNullable(configValue("PIN"))
.orElseThrow(() -> new IllegalStateException("PIN не задан"));
System.out.println(value);
} catch (IllegalStateException e) {
System.out.println("Ошибка: " + e.getMessage());
}
}
}
Output:
Ошибка: PIN не задан
Пример 5. Поиск в коллекции
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class OptionalFind {
public static void main(String[] args) {
List<String> sensors = Arrays.asList("ИК", "УЗ", "Линия");
Optional<String> found = sensors.stream()
.filter(s -> s.startsWith("У"))
.findFirst();
System.out.println("Найдено: " + found.orElse("ничего"));
Optional<String> missing = sensors.stream()
.filter(s -> s.equals("GPS"))
.findFirst();
System.out.println("GPS: " + missing.orElse("нет такого"));
}
}
Output:
Найдено: УЗ
GPS: нет такого
Пример 6. flatMap при вложенных Optional
import java.util.Optional;
public class OptionalFlatMap {
static Optional<String> findUser(int id) {
return id == 1 ? Optional.of("Айтен") : Optional.empty();
}
static Optional<String> findEmail(String user) {
return user.equals("Айтен") ? Optional.of("aiten@example.com") : Optional.empty();
}
public static void main(String[] args) {
String email = findUser(1)
.flatMap(OptionalFlatMap::findEmail)
.orElse("не найден");
System.out.println(email);
String none = findUser(2)
.flatMap(OptionalFlatMap::findEmail)
.orElse("не найден");
System.out.println(none);
}
}
Output:
aiten@example.com
не найден
Подводные камни
Предупреждение
Не вызывайте
get()без предварительной проверки — это та жеNullPointerException, только в другой обёртке.Не используйте
Optionalдля полей классов и параметров методов — по официальной рекомендации это тип для возвращаемого значения.Optional.of(null)броситNullPointerException. Если значение может бытьnull, беритеOptional.ofNullable.orElse(x)всегда вычисляетx, даже если значение есть. Еслиx— дорогой вызов, используйтеorElseGet(() -> x).Optionalне предназначен для сериализации — он неSerializable.
См. также
Примечание
Материал подготовлен по мотивам документации классов java.util.Optional
и java.util.stream и распространяется в рамках Oracle Free Documentation
License. Текст написан своими словами, примеры кода — оригинальные.