Перейти к основному содержимому

Улучшения Java 9 CompletableFuture API

· 5 мин. чтения

1. Введение

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

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

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

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

  1. Исполнитель по умолчаниюExecutor()
  2. CompletableFuture<U> newIncompleteFuture()
  3. CompletableFuture<T> копировать()
  4. CompletionStage<T> минимальныйCompletionStage()
  5. CompletableFuture<T> completeAsync (поставщик <? расширяет поставщика T>, исполнитель-исполнитель)
  6. CompletableFuture<T> completeAsync (поставщик<? расширяет поставщика T>)
  7. CompletableFuture<T> orTimeout (длительный тайм-аут, блок TimeUnit)
  8. CompletableFuture<T> completeOnTimeout (значение T, длительное время ожидания, единица измерения TimeUnit)

2.1. Метод defaultExecutor()

Подпись : Исполнитель defaultExecutor()

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

new CompletableFuture().defaultExecutor()

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

2.2. Метод newIncompleteFuture()

Подпись : CompletableFuture<U> newIncompleteFuture()

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

new CompletableFuture().newIncompleteFuture()

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

2.3. Метод копирования()

Подпись : CompletableFuture<T> копировать()

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

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

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

2.4. Метод MinimumCompletionStage()

Подпись : CompletionStage<T> 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<T> orTimeout (длительный тайм-аут, блок TimeUnit)

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

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

2.7. Метод CompleteOnTimeout()

Подпись : CompletableFuture<T> completeOnTimeout (значение T, длительное время ожидания, единица измерения TimeUnit)

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

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

3. Дополнения статического API

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

  1. Executor delayedExecutor (длительная задержка, модуль TimeUnit, исполнитель Executor)
  2. Executor delayedExecutor (длительная задержка, блок TimeUnit)
  3. <U> CompletionStage<U> CompletedStage (значение U)
  4. <U> CompletionStage<U> failedStage (выбрасываемый 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 , либо завершенные нормально со значением ( completeStage ), либо завершенные исключительно ( failedStage ) с заданным исключением.

3.3. Метод не выполнен Будущее

Подпись : <U> CompletableFuture<U> failedFuture (Throwable ex)

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

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

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

4.1. Задерживать

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

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

4.2. Завершить со значением по тайм-ауту

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

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

4.3. Тайм-аут

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

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

5. Вывод

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

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

Примеры, использованные в этой статье, можно найти в нашем репозитории GitHub .