Как вы применяете функциональное программирование в Java?

«Как вы применяете функциональное программирование в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Java функциональные возможности активно используются, начиная с версии 8. Основные инструменты:

1. Функциональные интерфейсы и лямбда-выражения:

  • Predicate<T> — проверка условия (test(T t)).
  • Function<T,R> — преобразование объекта (apply(T t)).
  • Consumer<T> — выполнение действия (accept(T t)).
  • Supplier<T> — поставщик значения (get()).

Пример: Замена анонимного класса на лямбду.

// До Java 8
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Clicked");
    }
});
// С Java 8
button.addActionListener(e -> System.out.println("Clicked"));

2. Stream API: Позволяет работать с коллекциями в декларативном стиле.

List<String> names = Arrays.asList("Alice", "Bob", "Anna", "Alex");
List<String> result = names.stream()
        .filter(name -> name.startsWith("A")) // Промежуточная операция (Predicate)
        .map(String::toUpperCase)            // Промежуточная операция (Function)
        .sorted()
        .collect(Collectors.toList());       // Терминальная операция
// Результат: ["ALEX", "ALICE", "ANNA"]

3. Optional: Контейнер для защиты от NullPointerException. Поощряет явную проверку на null.

Optional<User> user = userRepository.findById(id);
user.ifPresent(u -> System.out.println(u.getName())); // Действие, если значение есть
String name = user.map(User::getName).orElse("Default"); // Извлечение с fallback

4. Другие применения:

  • CompletableFuture для асинхронного программирования с цепочками вызовов (thenApply, thenAccept).
  • Методы Comparator.comparing() для функционального создания компараторов.

Почему это важно: Функциональный стиль делает код более выразительным, лаконичным и легким для параллельного выполнения (через parallelStream()). Он способствует созданию чистых функций без побочных эффектов, что упрощает тестирование и понимание кода. Однако важно знать и императивный стиль для оптимизации критичных по производительности участков.