«1. Введение

Java 9 поставляется с некоторыми изменениями в классе CompletableFuture. Такие изменения были введены как часть JEP 266 для решения общих жалоб и предложений с момента его появления в JDK 8, в частности, поддержка задержек и тайм-аутов, улучшенная поддержка подклассов и несколько служебных методов.

С точки зрения кода API поставляется с восемью новыми методами и пятью новыми статическими методами. Чтобы включить такие дополнения, было изменено примерно 1500 из 2400 строк кода (согласно Open JDK).

2. Дополнения API экземпляров

Как уже упоминалось, API экземпляров поставляется с восемью новыми дополнениями, а именно:

  1. Executor defaultExecutor()
  2. CompletableFuture<U> newIncompleteFuture()
  3. CompletableFuture<T> copy()
  4. CompletionStage<T> minimalCompletionStage()
  5. CompletableFuture<T> completeAsync(Supplier<? extends T> supplier, Executor executor)
  6. CompletableFuture<T> completeAsync(Supplier<? extends T> supplier)
  7. CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
  8. CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)

2.1. Метод defaultExecutor()

Подпись: Executor defaultExecutor()

Возвращает Executor по умолчанию, используемый для асинхронных методов, которые не указывают Executor.

new CompletableFuture().defaultExecutor()

Это может быть переопределено подклассами, возвращающими исполнителя, обеспечивающего, по крайней мере, один независимый поток.

2.2. Метод newIncompleteFuture()

Сигнатура: CompletableFuture\u003cU\u003e newIncompleteFuture()

Метод newIncompleteFuture, также известный как «виртуальный конструктор», используется для получения нового завершаемого экземпляра будущего того же типа.

new CompletableFuture().newIncompleteFuture()

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

2.3. Метод copy()

Подпись: CompletableFuture\u003cT\u003e copy()

Этот метод возвращает новый CompletableFuture, который:

    Когда это завершается нормально, новое также завершается нормально Когда это завершается исключительно с исключением X, новый также завершается в исключительных случаях с CompletionException с X в качестве причины
new CompletableFuture().copy()

Этот метод может быть полезен как форма «защитного копирования», чтобы предотвратить завершение клиентов, но при этом иметь возможность организовать зависимые действия над конкретным экземпляром CompletableFuture.

2.4. Метод MinimumCompletionStage()

Сигнатура: CompletionStage\u003cT\u003e MinimumCompletionStage()

Этот метод возвращает новый CompletionStage, который ведет себя точно так же, как описано в методе копирования, однако такой новый экземпляр генерирует исключение UnsupportedOperationException при каждой попытке получить или установить разрешенное значение.

new CompletableFuture().minimalCompletionStage()

Новый объект CompletableFuture со всеми доступными методами можно получить с помощью метода toCompletableFuture, доступного в API CompletionStage.

2.5. Методы completeAsync()

Метод completeAsync следует использовать для асинхронного завершения CompletableFuture с использованием значения, предоставленного поставщиком.

Сигнатуры:

CompletableFuture<T> completeAsync(Supplier<? extends T> supplier, Executor executor)
CompletableFuture<T> completeAsync(Supplier<? extends T> supplier)

Отличие этих двух перегруженных методов заключается в наличии второго аргумента, в котором можно указать Исполнителя, выполняющего задачу. Если ничего не указано, будет использоваться исполнитель по умолчанию (возвращенный методом defaultExecutor).

2.6. Методы orTimeout()

Сигнатура: CompletableFuture\u003cT\u003e orTimeout(длительный тайм-аут, модуль TimeUnit)

new CompletableFuture().orTimeout(1, TimeUnit.SECONDS)

Исключительно разрешает CompletableFuture с TimeoutException, если только он не завершен до указанного тайм-аута.

2.7. Метод CompleteOnTimeout()

Сигнатура: CompletableFuture\u003cT\u003e completeOnTimeout(T value, long timeout, TimeUnit unit)

new CompletableFuture().completeOnTimeout(value, 1, TimeUnit.SECONDS)

Обычно завершает CompletableFuture с указанным значением, если только оно не завершается до указанного времени ожидания.

3. Добавление статического API

Также были добавлены некоторые служебные методы. Вот они:

  1. Executor delayedExecutor(long delay, TimeUnit unit, Executor executor)
  2. Executor delayedExecutor(long delay, TimeUnit unit)
  3. <U> CompletionStage<U> completedStage(U value)
  4. <U> CompletionStage<U> failedStage(Throwable ex)
  5. <U> CompletableFuture<U> failedFuture(Throwable ex)

3.1. Методы delayedExecutor

Сигнатуры:

Executor delayedExecutor(long delay, TimeUnit unit, Executor executor)
Executor delayedExecutor(long delay, TimeUnit unit)

Возвращает новый Executor, который отправляет задачу данному базовому исполнителю после заданной задержки (или без задержки, если результат неположительный). Каждая задержка начинается при вызове метода execute возвращенного исполнителя. Если исполнитель не указан, будет использоваться исполнитель по умолчанию (ForkJoinPool.commonPool()).

3.2. Методы completeStage и failedStage

Подписи:

<U> CompletionStage<U> completedStage(U value)
<U> CompletionStage<U> failedStage(Throwable ex)

«

«Методы этой утилиты возвращают уже разрешенные экземпляры CompletionStage, либо завершенные нормально со значением (completedStage), либо завершенные исключительно (failedStage) с заданным исключением.

3.3. Метод failedFuture

Сигнатура: \u003cU\u003e CompletableFuture\u003cU\u003e failedFuture(Throwable ex)

Метод failedFuture добавляет возможность указать уже завершенный исключительный экземпляр CompleatebleFuture.

4. Примеры использования

В этом разделе будет показано несколько примеров использования некоторых новых API.

4.1. Задержка

CompletableFuture<Object> future = new CompletableFuture<>();
future.completeAsync(() -> input, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS));

В этом примере показано, как отложить завершение CompletableFuture с определенным значением на одну секунду. Этого можно добиться, используя метод completeAsync вместе с delayedExecutor.

4.2. Complete With Value on Timeout

CompletableFuture<Object> future = new CompletableFuture<>();
future.completeOnTimeout(input, 1, TimeUnit.SECONDS);

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

4.3. Тайм-аут

CompletableFuture<Object> future = new CompletableFuture<>();
future.orTimeout(1, TimeUnit.SECONDS);

Другой возможностью является тайм-аут, который разрешает будущее исключительно с помощью TimeoutException. Например, время ожидания CompletableFuture истекло через 1 секунду, если оно не было завершено до этого.

5. Заключение

В заключение, Java 9 поставляется с несколькими дополнениями к API CompletableFuture, теперь в нем улучшена поддержка подклассов, благодаря виртуальному конструктору newIncompleteFuture появилась возможность взять под контроль CompletionStage экземпляры возвращаются в большинстве API CompletionStage.

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