CompletableFuture

CompletableFuture используется для построения пайплайна (сколь угодно ветвящегося) при обработке ассинхронных событий, во избежание callback hell.

CompletableFuture наследуется от CompletionStage и Future, но в отличии от Future - CompletableFuture может быть явно закомпличена.

CompletableFuture - фреймворк для обработки асинхронных событий, объекты которого используются часто и во внутренних библиотеках java, как возвращаемое значения выполнеения какого нибудь ассинхронного действия.

T get(...)

См. Future

T join()

Так же как и get ожидает завершения и возвращает значение, но в отличие от get кидает unchecked exceptions (CompletionException - if this future completed exceptionally or a completion computation threw an exception).

T getNow​(T valueIfAbsent)

Если задача еше не была выполнена - возвращается valueIfAbsent.

Добавлено в Java 8

Способы создания CompletableFuture

new

Создает незакомпличенное CompletableFuture.

Что бы закомплитить явно, нужно вызвать один из методов:

boolean cancel

If not already completed, completes this CompletableFuture with a CancellationException.

boolean complete​(T value)

If not already completed, sets the value returned by get and related methods (join…) to the given value.

boolean completeExceptionally​(Throwable ex)

If not already completed, causes invocations of get and related methods (join…) to throw the given exception.

(См. Обработка ошибок)

CompletableFuture<T> completeAsync​(Supplier<out T> supplier[, Executor executor])

Completes this CompletableFuture with the result of the given Supplier function invoked from an asynchronous task.

Returns this CompletableFuture.

CompletableFuture<T> completeOnTimeout​(T value, long timeout, TimeUnit unit)

Completes this CompletableFuture with the given value if not otherwise completed before the given timeout.

Returns this CompletableFuture.

static completedFuture​(U value)

Возвращает новое CompletableFuture<U>, которое уже закомпличено заданным значением.

static supplyAsync​(Supplier<U> supplier[, Executor executor])

Returns a new CompletableFuture<U> которая комплитится, как только выполнится переданное действие (асинхронно).

static runAsync​(Runnable runnable[, Executor executor])

Returns a new CompletableFuture<Void> которая комплитится, как только выполнится переданное действие (асинхронно).

Note

Сейчас и далее для всех асинхронных операций (*Async - напр thenApplyAsync​): если Executor не указан - выбирается для исполнения commonPool (а там все потоки демоны).

Объединение и пересечение результатов

static CompletableFuture<Void> allOf​(CompletableFuture<?>... cfs)

Возвращает новое CompletableFuture, которое комплитится после завершения всех заданных CompletableFutures.

static CompletableFuture<Object> anyOf​(CompletableFuture<?>... cfs)

Возвращает новое CompletableFuture, которое комплитится, когда завершается хоть одно из заданных CompletableFutures, с тем же результатом.

CompletionStage

CompletionStage - Этап асинхронного (возможно) вычисления, выполняющееся, когда завершается другой CompletionStage.

Async функции (*Async - напр thenApplyAsync​) выполняются в другом (указанном или commonPool) executor’е, нежели в том потоке, где происходило предыдущее действие. В противоположность не async-функциям, которые выполняются в том же потоке, где действие происходит. Но если действие уже было завершено - выполнение происходит в текущем потоке (в том откуда вызвана функция на CompletionStage).

На один и тот-же CompletionStage можно прицепить несколько обработчиков, при этом если они не async - они будут выпоняться последовательно в последнем потоке обработки (если действие описанное в обработчике не завершилось) или в текущем потоке (если предыдущее действие завершилось). После выполнения всех действий - проверяется, нет ли еще обработчиков, которые нужно в данном потоке прогнать, и если их нет - работа в этом потоке завершается. Поэтому если выполнение завершено и добавляется еще действие в пайплайне - то это действие уже будет происходить в текущем потоке.

Tip

Стоит помнить, что при модификациях разделяемой памяти из разных витков CompletionStage - модифицируется все равно один и тот же объект:


Note

Для всех ниже перечисленных методов на CompletionStage доступны парные async-методы (кроме exceptionally​) с опциональным параметром (Executor executor), выполняемые асинхронно, либо в указаном Executor’е, либо в FJP.commonPool .

Подписка

thenRun​(Runnable action)

Выполняет специфицированное действие, при завершении выполнения предыдущего в пайплайне. Возвращает CompletionStage<Void>.

thenAccept​(Consumer<? super T> action)

Выполняет специфицированное действие принимая значение полученное из предыдущего в пайплайне. Возвращает CompletionStage<Void>.

Трансформация (map)

thenApply​(Function<? super T,? extends U> fn)

Преобразует оборачиваемое значение внутри CompletionStage.

Комбинация (reduce)

thenCombine​(CompletionStage<out U> other, BiFunction<in T,in U,out V> fn)

Ожидает выполнения двух этапов (CompletionStage<T> и CompletionStage<U>) и склеивает их функцией fn.

Композиция (flatMap)

thenCompose​(Function<in T,out CompletionStage<U>> fn)

Преобразует один CompletionStage в зависимый от него другой CompletionStage (возвращает новый CompletionStage, который завершается тем же значением, что и CompletionStage, возвращаемый данной функцией).

Обработка ошибок

join запихнет ошибку в CompletionException, а get в ExecutionException.

Note

Ошибка пробрасывается по цепочкам, т.е. обработчики ожидающие значение, а принимающие ошибку - не будут выполняться, а лишь пробросят ошибку далее.

exceptionally​(Function<Throwable,out T> fn)

Функция fn применяется, если на одном из предыдущих обработчиков в пайплайне было брошено исключение. При этом от момента исключения до метода exceptionally​, обработчики не будут выполняться (ошибка пробрасывается по цепочкам), и наоборот exceptionally​ не будет выполняться, если не было получено исключение.

handle​(BiFunction<? super T,Throwable,? extends U> fn)

Так же как exceptionally​ принимает исключение, но наряду с ним так же принимает предыдущее значение из пайплайна. Не трудно догадаться что либо исключение, либо значение от пред. обработчика будет == null.