Java 8 – CompletableFuture vs Future


CompletableFuture vs Future

Z tego wpisu dowiesz się czym jest interfejs CompletableFuture oraz jakie są różnice między dwoma interfejsami – CompletableFuture vs Future:

CompletableFuture to klasa implementująca dwa interfejsy:

  • Future
  • CompletionStage

Future to obiekt który przechowuje wynik asynchronicznych obliczeń. Obliczenia te można przekazać dalej w programie a kiedy będą gotowe właściciel obiektu może je pobrać. Interfejs Future nie udostępnia jednak możliwości ręcznego zakończenia operacji pobierania wyników. Jeśli przetwarzanie trwa zbyt długo to program się blokuje. W javie 8 wprowadzono interfejs CompletableFuture który to pozwala ręcznie zakończyć procedurę przetwarzania wyników – wynik wtedy zwracany jest od razu:

completableFuture.completedFuture("JavaLeader.pl");

Interfejs Future nie daje możliwości wywołania metod zwrotnych typu callback w momencie kiedy dane przetwarzanie jest zakończone. Zanim przejdziemy do metod typu callback przyjrzyjmy się następującym metodom – runAsync() oraz supplyAsync():

  • runAsync()
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
    System.out.println("Running asynchronous task in parallel");
    TimeUnit.SECONDS.sleep(1);
 } catch (InterruptedException ex) {
    throw new IllegalStateException(ex);
    }
});

W tym przypadku wykonywane są tylko pewne asynchroniczne działania w tle. Jako argument do metody runAsync() przyjmowana jest implementacja interfejsu Runnable. Druga z kolei metoda jako argument przyjmuje implementację interfejsu Supplier i zwraca wynik swojego przetwarzania:

  • supplyAsync()
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
    TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
    throw new IllegalStateException(e);
}
    return "This is the result of the asynchronous computation";
});

Metody typu callable:

  • thenApply() – wynik przetwarzania przekazany jest do zdefiniowanej funkcji callback – jako argument przekazywana jest implementacja interfejsu Function:
CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> {
try {
    TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
    throw new IllegalStateException(e);
}
    return "JavaLeader.pl!";
});
CompletableFuture result = completableFuture.thenApply(name -> "Welcome" + name);

lub – funkcja callback przekazuje wynik do kolejnej funkcji typu callback:

CompletableFuture result = CompletableFuture.supplyAsync(() -> {
try {
    TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
    throw new IllegalStateException(e);
}
return "JavaLeader";
})
.thenApply(name -> "Welcome " + name)
.thenApply(greeting -> greeting + ".pl");
  • thenAccept() – jako argument przyjmowana jest implementacja interfejsu BiConsumer:
CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> "JavaLeader.pl!");
CompletableFuture result = completableFuture.thenAccept(value -> System.out.println("Welcome" + value));

Różnicę między thenApply() a thenAccept() ilustruje poniżej zamieszczony przykład:

CompletableFuture.completedFuture("FUTURE")
    .thenApply(f -> f.toLowerCase())
    .thenAccept(f -> System.out.println(f))
    .thenAccept(f -> System.out.println(f))
    .thenApply(f -> new String("FUTURE"))
    .thenAccept(f -> System.out.println(f));

wynik:

future
null
FUTURE

thenApply() przekazuje wynik dalej. ThenAccept nie przechowuje wartości i zwraca void.

  • thenRun() jako argument przyjmowana jest implementacja interfejsu Runnable:
CompletableFuture completableFuture
= CompletableFuture.supplyAsync(() -> "JavaLeader.pl!");
CompletableFuture result
= completableFuture.thenRun(() -> System.out.println("Example with thenRun()."));

 


Leave a comment

Your email address will not be published.


*