Получить доступ

Какое ограничение Future решает CompletableFuture?

MiddleМногопоточность
Ещё спрашивают так:
  • Чем CompletableFuture лучше обычного Future и как в нём обрабатывают ошибки?
Коротко

Future — дескриптор результата с единственным способом получить значение: блокирующий get(). CompletableFuture позволяет описать цепочку продолжений (thenApply, thenCompose, thenCombine, allOf), которая выполнится по готовности, — без блокировки потока.

  • Ошибка едет по цепочке, минуя then-этапы, до exceptionally или handle
  • join и get оборачивают исключение в CompletionException или ExecutionException
  • Можно завершить вручную: complete, completeExceptionally

А ещё Async-стадии без своего executor идут в общий commonPool

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Ограничения Future: результат забирают блокирующим get(). Чтобы объединить два асинхронных вызова, нужно заблокировать поток на каждом. Колбэков нет, комбинировать нельзя.

CompletableFuture реализует Future и CompletionStage:

CompletableFuture<User> user = supplyAsync(() -> loadUser(id), io);
CompletableFuture<List<Order>> orders = supplyAsync(() -> loadOrders(id), io);
user.thenCombine(orders, Profile::new)
    .thenApply(this::render)
    .exceptionally(e -> fallbackPage())
    .thenAccept(this::send);
  • thenApply — преобразовать значение;
  • thenCompose — следующий шаг сам асинхронный (развернуть вложенный);
  • thenCombine — объединить два независимых результата;
  • allOf, anyOf — ждать группу.

Ошибки. Исключение в стадии не летит сразу: future завершается с ошибкой, следующие then* пропускаются, пока не встретится exceptionally, handle или whenComplete. При join() исключение приходит в CompletionException, при get() — в ExecutionException; настоящая причина — в getCause().

Потоки. Продолжение без суффикса Async может выполниться в потоке, завершившем предыдущую стадию, или в вызывающем. Async-варианты без аргумента используют ForkJoinPool.commonPool() — блокирующие операции отдают в свой executor.

Что хотят услышать

  • Блокирующий get и отсутствие композиции у Future.
  • Основные операции композиции.
  • Как распространяется и обрабатывается ошибка.
  • Где выполняются стадии.

Частые ошибки

  • Вызывать get внутри цепочки, превращая её снова в блокирующую.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓У Future get() блокирует поток и нет композиции/колбэков; CompletableFuture добавляет неблокирующие продолжения и сцепление операций
  • ✗Future нельзя отменить, а CompletableFuture можно
  • ✗Future не умеет возвращать результат, а CompletableFuture умеет
  • ✗Future работает только в одном потоке

Что спросят дальше

  • Что делает supplyAsync против runAsync?
  • Как объединить два независимых CompletableFuture?
  • Чем thenApply отличается от thenCompose?
  • Что изменилось с приходом структурной конкурентности?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем