← Назад к вопросам

Какие знаешь методы Optional?

1.8 Middle🔥 121 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Методы класса Optional в Java

Optional<T> - это контейнер, который может содержать или не содержать значение. Он помогает избежать NullPointerException и делает код более выразительным. Рассмотрю все ключевые методы с примерами.

1. Создание Optional

import java.util.Optional;

public class OptionalCreation {
    public static void main(String[] args) {
        // 1. Optional.of() - значение обязательно есть
        Optional<String> opt1 = Optional.of("hello");
        // Optional.of(null) -> NullPointerException
        
        // 2. Optional.ofNullable() - значение может быть null
        Optional<String> opt2 = Optional.ofNullable(null);   // Empty
        Optional<String> opt3 = Optional.ofNullable("world"); // Present
        
        // 3. Optional.empty() - пустой Optional
        Optional<String> empty = Optional.empty();
        
        // 4. Stream -> Optional
        Optional<String> fromStream = java.util.stream.Stream.of("test")
            .findFirst();  // Optional<String>
    }
}

2. Проверка наличия значения

public class OptionalChecking {
    public static void main(String[] args) {
        Optional<String> opt = Optional.of("hello");
        
        // 1. isPresent() - есть ли значение
        if (opt.isPresent()) {
            System.out.println("Value exists: " + opt.get());
        }
        
        // 2. isEmpty() - пуст ли (Java 11+)
        if (opt.isEmpty()) {
            System.out.println("Optional is empty");
        }
        
        // 3. ifPresent() - выполнить если есть значение
        opt.ifPresent(value -> System.out.println("Value: " + value));
        
        // 4. ifPresentOrElse() - if-else логика (Java 9+)
        opt.ifPresentOrElse(
            value -> System.out.println("Found: " + value),
            () -> System.out.println("Not found")
        );
        
        // 5. Использовать в условии
        String result = opt.isPresent() ? opt.get() : "default";
    }
}

3. get() и orXyz() методы

public class OptionalGet {
    public static void main(String[] args) {
        Optional<String> opt = Optional.ofNullable(null);
        
        // 1. get() - получить значение или выбросить исключение
        try {
            String value = opt.get();  // NoSuchElementException если пусто
        } catch (java.util.NoSuchElementException e) {
            System.out.println("No value present");
        }
        
        // 2. orElse() - вернуть значение или default
        String value1 = opt.orElse("default");
        System.out.println(value1);  // "default"
        
        // 3. orElseGet() - вызвать функцию если пусто (ленивое вычисление)
        String value2 = opt.orElseGet(() -> getDefaultValue());
        
        // 4. orElseThrow() - выбросить исключение если пусто
        String value3 = opt.orElseThrow();
        // или с кастомным исключением
        String value4 = opt.orElseThrow(
            () -> new IllegalArgumentException("Value not found")
        );
        
        // 5. or() - вернуть другой Optional если пусто (Java 9+)
        Optional<String> value5 = opt.or(() -> Optional.of("fallback"));
    }
    
    private static String getDefaultValue() {
        System.out.println("Computing default...");
        return "computed";
    }
}

4. map() и flatMap() - трансформация значений

public class OptionalMap {
    public static class User {
        String name;
        Optional<String> email;  // может не быть email
        
        public User(String name, String email) {
            this.name = name;
            this.email = Optional.ofNullable(email);
        }
    }
    
    public static void main(String[] args) {
        Optional<User> user = Optional.of(new User("Alice", "alice@example.com"));
        
        // 1. map() - трансформировать значение
        Optional<String> emailLength = user.map(u -> u.email.orElse("N/A"))
                                            .map(String::length);
        // Optional<Integer>
        
        // 2. flatMap() - для Optional возвращающих методов
        Optional<String> userEmail = user.flatMap(u -> u.email);
        // Без flatMap пришлось бы писать: user.map(u -> u.email).flatMap(e -> e)
        
        // 3. Цепочка трансформаций
        Optional<Integer> result = user
            .flatMap(u -> u.email)           // Optional<String>
            .map(String::length)             // Optional<Integer>
            .filter(len -> len > 0)          // Optional<Integer>
            .map(len -> len * 2);            // Optional<Integer>
        
        System.out.println(result.orElse(0));
    }
}

5. filter() - фильтрация

public class OptionalFilter {
    public static void main(String[] args) {
        Optional<Integer> age = Optional.of(25);
        
        // 1. filter() - оставить если условие true
        Optional<Integer> adult = age.filter(a -> a >= 18);
        System.out.println(adult.orElse(0));  // 25
        
        // 2. filter выбросит пусто если условие false
        Optional<Integer> minor = Optional.of(15)
            .filter(a -> a >= 18);
        System.out.println(minor.orElse(0));  // 0 (empty)
        
        // 3. Валидация данных
        Optional<String> email = Optional.of("user@example.com");
        Optional<String> validEmail = email.filter(e -> e.contains("@"));
        
        // 4. Цепочка фильтров
        Optional<Integer> result = Optional.of(42)
            .filter(n -> n > 0)         // положительное
            .filter(n -> n < 100)       // меньше 100
            .filter(n -> n % 2 == 0);   // чётное
    }
}

6. Практические примеры

public class OptionalPracticalExamples {
    // ПЛОХО: без Optional
    public String getUserNameBad(Long userId) {
        User user = findUserById(userId);
        if (user != null) {
            if (user.getProfile() != null) {
                return user.getProfile().getName();
            }
        }
        return "Unknown";
    }
    
    // ХОРОШО: с Optional
    public String getUserNameGood(Long userId) {
        return findUserByIdOptional(userId)
            .flatMap(user -> user.getProfile())
            .map(Profile::getName)
            .orElse("Unknown");
    }
    
    // Вспомогательные методы
    private Optional<User> findUserByIdOptional(Long userId) {
        return Optional.ofNullable(findUserById(userId));
    }
    
    private User findUserById(Long userId) {
        return null;  // или БД запрос
    }
}

public class Profile {
    private String name;
    public String getName() { return name; }
}

public class User {
    private Profile profile;
    public Optional<Profile> getProfile() {
        return Optional.ofNullable(profile);
    }
}

7. Работа со Stream и Optional

import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.Collectors;

public class OptionalWithStream {
    public static void main(String[] args) {
        // 1. stream() - преобразовать Optional в Stream
        Optional<String> opt = Optional.of("hello");
        opt.stream()
           .forEach(System.out::println);  // hello
        
        // 2. Фильтрирование списка Optional'ов
        java.util.List<Optional<String>> optionalList = java.util.Arrays.asList(
            Optional.of("one"),
            Optional.empty(),
            Optional.of("three")
        );
        
        java.util.List<String> values = optionalList.stream()
            .flatMap(Optional::stream)  // раскрыть Optional в Stream
            .collect(Collectors.toList());
        // ["one", "three"]
        
        // 3. findFirst() и findAny() возвращают Optional
        Optional<Integer> first = java.util.Arrays.asList(1, 2, 3).stream()
            .findFirst();  // Optional<Integer>
        
        // 4. Использовать Optional как sentinel
        java.util.List<String> names = java.util.Arrays.asList("Alice", "Bob", "Charlie");
        Optional<String> found = names.stream()
            .filter(name -> name.startsWith("B"))
            .findFirst();
        found.ifPresent(System.out::println);  // Bob
    }
}

8. Optional в параметрах функций

public class OptionalAsParameter {
    // ПЛОХО: не используй Optional в параметрах
    // public void processOptional(Optional<String> value) { }
    
    // ХОРОШО: используй обычный параметр
    public void processValue(String value) {
        if (value != null) {
            // логика
        }
    }
    
    // ХОРОШО: параметр явно указывает что может быть null
    public void processNullable(String value) {
        // Использовать @Nullable аннотацию
        if (value != null) {
            // логика
        }
    }
    
    // Исключение: возвращаемые значения
    public Optional<String> findValue(String key) {
        return Optional.ofNullable(computeValue(key));
    }
}

9. Таблица методов Optional

Метод              | Возвращает      | Описание
---
of(T)              | Optional<T>     | Значение обязательно есть
ofNullable(T)      | Optional<T>     | Может быть null
empty()            | Optional<T>     | Пустой Optional
get()              | T               | Значение или исключение
orElse(T)          | T               | Значение или default
orElseGet(Supplier)| T               | Значение или функция
orElseThrow()      | T               | Значение или исключение
or(Supplier)       | Optional<T>     | Этот или другой Optional
isPresent()        | boolean         | Есть ли значение
isEmpty()          | boolean         | Пуст ли
ifPresent(Consumer)| void            | Выполнить если есть
ifPresentOrElse()  | void            | If-else логика
map(Function)      | Optional<U>     | Трансформировать
flatMap(Function)  | Optional<U>     | Трансформировать с раскрытием
filter(Predicate)  | Optional<T>     | Отфильтровать
stream()           | Stream<T>       | Преобразовать в Stream

10. Anti-patterns - что НЕ делать

public class OptionalAntiPatterns {
    public static void main(String[] args) {
        Optional<String> opt = Optional.of("test");
        
        // ПЛОХО: if (opt.isPresent()) { opt.get() }
        // ХОРОШО:
        opt.ifPresent(System.out::println);
        
        // ПЛОХО: Optional в параметрах
        // processOptional(Optional.of("test"));
        // ХОРОШО:
        processValue("test");
        
        // ПЛОХО: obj == null ? Optional.of(obj) : Optional.empty()
        // ХОРОШО:
        Optional.ofNullable(null);
        
        // ПЛОХО: opt.isPresent() && opt.get().equals(...)
        // ХОРОШО:
        opt.filter(v -> v.equals("test")).ifPresent(System.out::println);
        
        // ПЛОХО: opt.map(x -> null)
        // ХОРОШО: используй flatMap
    }
    
    private static void processValue(String value) {
        if (value != null) {
            // логика
        }
    }
}

Итоговые правила

  1. Используй Optional для возвращаемых значений, не для параметров
  2. Никогда не используй Optional.get() без проверки isPresent()
  3. Используй map/flatMap/filter вместо if-else цепочек
  4. Используй ifPresent/ifPresentOrElse для side-effects
  5. Optional облегчает null-safety - основная цель
  6. НЕ используй Optional для примитивов - есть OptionalInt, OptionalLong
  7. Optional - это не замена null checks, а инструмент для более понятного кода