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