Каковы преимущества и недостатки CompletableFuture в Java?

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

Ответ

CompletableFuture — это мощное расширение Future, представляющее результат асинхронного вычисления с возможностью явного завершения и комбинирования.

Преимущества:

  • Комбинация и цепочка вызовов: Позволяет создавать сложные асинхронные конвейеры, комбинируя результаты нескольких фьючерсов (например, thenApply, thenCombine, allOf).
  • Явное завершение: Можно вручную завершить фьючерс с результатом (complete) или исключением (completeExceptionally).
  • Неблокирующая обработка: Поддержка callback-функций (thenAccept, whenComplete) избавляет от необходимости блокирующего вызова get().
  • Обработка исключений: Встроенные методы для обработки ошибок в цепочке (exceptionally, handle).
  • Гибкость выполнения: Можно явно указать Executor для каждого этапа.

Недостатки и сложности:

  • Сложность отладки: Асинхронные цепочки сложнее отлаживать, чем последовательный код. Стек вызовов может быть неинформативным.
  • Риск утечки памяти: Если цепочка не завершится (например, из-за необработанного исключения), ссылки на объекты могут не освобождаться.
  • Ошибка по умолчанию: Необработанные исключения в цепочке могут быть «проглочены» без явной обработки.
  • Когнитивная нагрузка: Сложный API требует глубокого понимания для эффективного и безопасного использования.

Пример: цепочка асинхронных операций

CompletableFuture.supplyAsync(() -> fetchDataFromService()) // Асинхронно получаем данные
    .thenApply(data -> processData(data)) // Обрабатываем результат
    .thenAccept(result -> System.out.println("Result: " + result)) // Потребляем результат
    .exceptionally(ex -> { // Обрабатываем ошибки на любом этапе
        System.err.println("Failed: " + ex.getMessage());
        return null;
    });