Miglioramenti all'API CompletableFuture di Java 9

1. Introduzione

Java 9 include alcune modifiche alla classe CompletableFuture . Tali modifiche sono state introdotte come parte di JEP 266 al fine di affrontare reclami e suggerimenti comuni sin dalla sua introduzione in JDK 8, più specificamente, supporto per ritardi e timeout, migliore supporto per sottoclassi e alcuni metodi di utilità.

Dal punto di vista del codice, l'API viene fornita con otto nuovi metodi e cinque nuovi metodi statici. Per abilitare tali aggiunte, sono state modificate circa 1500 righe di codice su 2400 (come da Open JDK).

2. Aggiunte API di istanza

Come accennato, l'API dell'istanza viene fornita con otto nuove aggiunte, sono:

  1. Esecutore defaultExecutor ()
  2. CompletableFuture newIncompleteFuture ()
  3. Completabile Copia futura ()
  4. CompletionStage minimalCompletionStage ()
  5. Completabile Futuro completo Asincrono (fornitore fornitore, esecutore esecutore)
  6. Completabile Futuro completo Async (fornitore fornitore)
  7. CompletableFuture o Timeout (timeout lungo, unità TimeUnit)
  8. CompletableFuture completeOnTimeout (valore T, timeout lungo, unità TimeUnit)

2.1. Metodo defaultExecutor ()

Firma : Executor defaultExecutor ()

Restituisce l' Executor predefinito utilizzato per i metodi asincroni che non specificano un Executor .

new CompletableFuture().defaultExecutor()

Questo può essere sovrascritto dalle sottoclassi che restituiscono un esecutore che fornisce, almeno, un thread indipendente.

2.2. Metodo newIncompleteFuture ()

Firma : CompletableFuture newIncompleteFuture ()

Il newIncompleteFuture , noto anche come "costruttore virtuale", viene utilizzato per ottenere una nuova istanza futura completabile dello stesso tipo.

new CompletableFuture().newIncompleteFuture()

Questo metodo è particolarmente utile quando si crea una sottoclasse CompletableFuture , principalmente perché viene utilizzato internamente in quasi tutti i metodi che restituiscono un nuovo CompletionStage , consentendo alle sottoclassi di controllare quale sottotipo viene restituito da tali metodi.

2.3. Copia metodo ()

Firma : Completabile Copia futura ()

Questo metodo restituisce un nuovo CompletableFuture che:

  • Quando questo viene completato normalmente, anche quello nuovo viene completato normalmente
  • Quando questo viene completato eccezionalmente con l'eccezione X, anche il nuovo viene completato eccezionalmente con una CompletionException con X come causa
new CompletableFuture().copy()

Questo metodo può essere utile come una forma di "copia difensiva", per impedire ai client di completare, pur essendo ancora in grado di organizzare azioni dipendenti su una specifica istanza di CompletableFuture .

2.4. Metodo minimalCompletionStage ()

Firma : CompletionStage minimalCompletionStage ()

Questo metodo restituisce un nuovo CompletionStage che si comporta esattamente nello stesso modo descritto dal metodo copy, tuttavia, tale nuova istanza genera UnsupportedOperationException in ogni tentativo di recuperare o impostare il valore risolto.

new CompletableFuture().minimalCompletionStage()

Un nuovo CompletableFuture con tutti i metodi disponibili può essere recuperato utilizzando il metodo toCompletableFuture disponibile sull'API CompletionStage .

2.5. Metodi completeAsync ()

Il metodo completeAsync deve essere utilizzato per completare il CompletableFuture in modo asincrono utilizzando il valore fornito dal fornitore fornito.

Firme :

CompletableFuture completeAsync(Supplier supplier, Executor executor) CompletableFuture completeAsync(Supplier supplier)

La differenza tra questi due metodi sovraccaricati è l'esistenza del secondo argomento, in cui è possibile specificare l' Executor che esegue l'attività. Se non viene fornito nessuno, verrà utilizzato l'esecutore predefinito (restituito dal metodo defaultExecutor ).

2.6. Metodi o Timeout ()

Firma : CompletableFuture o Timeout (timeout lungo, unità TimeUnit)

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

Risolve il CompletableFuture in modo eccezionale con TimeoutException , a meno che non venga completato prima del timeout specificato.

2.7. Metodo completeOnTimeout ()

Firma : CompletableFuture completeOnTimeout (valore T, timeout lungo, unità TimeUnit)

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

Completa il CompletableFuture normalmente con il valore specificato a meno che non venga completato prima del timeout specificato.

3. Aggiunte API statiche

Sono stati aggiunti anche alcuni metodi di utilità. Loro sono:

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

3.1. Methods delayedExecutor

Signatures:

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

Returns a new Executor that submits a task to the given base executor after the given delay (or no delay if non-positive). Each delay commences upon invocation of the returned executor's execute method. If no executor is specified the default executor (ForkJoinPool.commonPool()) will be used.

3.2. Methods completedStage and failedStage

Signatures:

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

This utility methods return already resolved CompletionStage instances, either completed normally with a value (completedStage) or completed exceptionally (failedStage) with the given exception.

3.3. Method failedFuture

Signature: CompletableFuture failedFuture(Throwable ex)

The failedFuture method adds the ability to specify an already completed exceptionally CompleatebleFuture instance.

4. Example Use Cases

Within this section, one will show some examples on how to use some of the new API.

4.1. Delay

This example will show how to delay the completion of a CompletableFuture with a specific value by one second. That can be achieved by using the completeAsync method together with the delayedExecutor.

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

4.2. Complete With Value on Timeout

Another way to achieve a delayed result is to use the completeOnTimeout method. This example defines a CompletableFuture that will be resolved with a given input if it stays unresolved after 1 second.

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

4.3. Timeout

Another possibility is timing out which resolves the future exceptionally with TimeoutException. For example, having the CompletableFuture timing out after 1 second given it is not completed before that.

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

5. Conclusion

In conclusione, Java 9 viene fornito con diverse aggiunte all'API CompletableFuture , ora ha un supporto migliore per le sottoclassi, grazie al nuovo costruttore virtuale IncompleteFuture , è possibile prendere il controllo delle istanze CompletionStage restituite nella maggior parte dell'API CompletionStage .

Ha, sicuramente, un supporto migliore per ritardi e timeout come mostrato in precedenza. I metodi di utilità aggiunti seguono uno schema ragionevole, offrendo a CompletableFuture un modo conveniente per specificare le istanze risolte.

Gli esempi utilizzati in questo articolo possono essere trovati nel nostro repository GitHub.