A Kompletna przyszłość służy do programowania asynchronicznego. Programowanie asynchroniczne oznacza pisanie kodu nieblokującego. Uruchamia zadanie w osobnym wątku niż główny wątek aplikacji i powiadamia główny wątek o jego postępie, zakończeniu lub niepowodzeniu.
W ten sposób główny wątek nie blokuje się i nie czeka na zakończenie zadania. Pozostałe zadania realizowane są równolegle. Równoległość poprawia wydajność programu.
CompletableFuture to klasa w Javie. Należy do pakietu java.util.cocurrent. Implementuje interfejs CompletionStage i Future.
Etap ukończenia
- Wykonuje akcję i zwraca wartość po zakończeniu kolejnego etapu zakończenia.
- Model zadania, które może wyzwalać inne zadania.
Jest zatem elementem łańcucha.
Gdy więcej niż jeden wątek próbuje zakończyć - wyjątkowo lub anulować CompletableFuture, tylko jeden z nich kończy się sukcesem.
sortuj tablicę w Javie
Przyszłość kontra pełna przyszłość
CompletableFuture jest rozszerzeniem Java Future API, które zostało wprowadzone w Javie 8.
Przyszłość jest używana do programowania asynchronicznego. Udostępnia dwie metody: isDone() i get(). Metody pobierają wynik obliczeń po ich zakończeniu.
Ograniczenia przyszłości
- Przyszłość nie może być wzajemnie kompletna.
- Nie możemy wykonać dalszych działań na wyniku Future bez blokady.
- Future nie ma żadnej obsługi wyjątków.
- Nie możemy łączyć wielu przyszłości.
Przyszłość ma tak wiele ograniczeń, dlatego mamy CompletableFuture. CompletableFuture zapewnia szeroki zestaw metod tworzenia wielu kontraktów Futures, łączenia ich w łańcuchy i łączenia. Posiada również kompleksową obsługę wyjątków.
Tworzenie kompletnej przyszłości
Możemy utworzyć CompletableFuture tylko przy użyciu następującego konstruktora bezargumentowego.
CompletableFuture CompletableFuture = new CompletableFuture();
Przykład
Najczęściej stosowane metody CompletableFuture to:
praca przy komputerze
import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; public class CompletableFutureExample1 { public static void main(String[] args) { try { List list = Arrays.asList(5,9,14); list.stream().map(num->CompletableFuture.supplyAsync(()->getNumber(num))).map(CompletableFuture->CompletableFuture.thenApply(n- >n*n)).map(t->t.join()).forEach(s->System.out.println(s)); } catch (Exception e) { e.printStackTrace(); } } private static int getNumber(int a) { return a*a; } }
Wyjście:
Obsługa wyjątków CompletableFuture
Rozważmy następujący rysunek, który przedstawia pięć CF:
Załóżmy, że wykonuje się pięć CF, a CF21 zgłasza wyjątek, wówczas wszystkie zależne CF (CF31 i CF41) zawierają błąd. To znaczy, że:
- Wywołanie metody isCompletedExceptionally() zwraca wartość true.
- Wywołanie metody get() zgłasza wyjątek ExecutionException, który powoduje wyjątek root.
Rozważmy następujący rysunek, na którym stworzyliśmy CF30 z wyjątkiem.
Kiedy CF21 działa normalnie, CF30 po prostu przesyła wartość. Jeśli zgłosi wyjątek, CF30 obsługuje go i generuje wartość dla CF31.
Istnieją trzy metody obsługi wyjątku:
public CompletableFuture exceptionally(Function function); public CompletableFuture hadle(BiFunction bifunction); public CompletableFuture whenComplete(BiConsumer action);