Какое ограничение Future решает CompletableFuture?
- Чем CompletableFuture лучше обычного Future и как в нём обрабатывают ошибки?
Future — дескриптор результата с единственным способом получить значение: блокирующий get(). CompletableFuture позволяет описать цепочку продолжений (thenApply, thenCompose, thenCombine, allOf), которая выполнится по готовности, — без блокировки потока.
- Ошибка едет по цепочке, минуя then-этапы, до exceptionally или handle
- join и get оборачивают исключение в CompletionException или ExecutionException
- Можно завершить вручную: complete, completeExceptionally
А ещё Async-стадии без своего executor идут в общий commonPool
Подробно
Ограничения 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 нельзя отменить, а CompletableFuture можно
- ✓get() у Future блокирует; CompletableFuture даёт неблокирующие продолжения
- ✗Future не умеет возвращать результат, а CompletableFuture умеет
- ✗Future работает только в одном потоке
Что спросят дальше
- Что делает supplyAsync против runAsync?
- Как объединить два независимых CompletableFuture?
- Чем thenApply отличается от thenCompose?
- Что изменилось с приходом структурной конкурентности?
Разбор темы
- Future и CompletableFuture
Ограничения Future, асинхронная композиция CompletableFuture, async-варианты с пулами и обработка ошибок.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.