Несколько дней новогоднего волшебства:
Успейте начать обучение в 2018-ом году со скидкой до 30%!
Выбрать курс

Асинхронный CompletableFuture. Часть 2

Java_Deep_22.06_3_Site.png

У CompletableFuture есть ещё интересные функции. Например, надо построить цепочку из асинхронных вызовов. Т.е. после завершения первой асинхронной функции запустить вторую, после второй третью и т.д. В JavaScript для этого применяются promise. В Java можно использовать CompletableFuture.

Выглядит это так:

private void thenApply() throws ExecutionException, InterruptedException {
        final CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
            System.out.println("job started");
            sleep(3);
            System.out.println("job done");
            return "feature done|";
        }).thenApply(result -> {
            System.out.println("applay result:" + result);
            return result + " applied";
        });
        System.out.println("waiting...");
        String result = future.get();
        System.out.println("finished, result:" + result);
    }

Сначала выполняется первая задача (sleep(3)) и только после её завершения запустится вторая задача. Причём второй задаче в качестве входного параметра можно передать результаты первой задачи.

А что делать с ошибками? Как их обрабатывать? У CompletableFuture есть встроенный механизм для обработки ошибок, применить его можно так:

private void thenApplyException() throws ExecutionException, InterruptedException {
        final CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
            System.out.println("job started");
            sleep(3);
            throw new RuntimeException("runTime exception");
        }).thenApply(result -> {
            System.out.println("applay result:" + result);
            return result + " applied";
        }).exceptionally(exception -> {
            System.out.println("got exception, err:" + exception.getMessage());
            return exception.getMessage();
        });
        System.out.println("waiting...");
        String result = future.get();
        System.out.println("finished, result:" + result);
    }

(*) Обратите внимание на блок exceptionally, он запустится, если одна из задач выбросит исключение.

У CompletableFuture есть ещё интересная возможность: запускать несколько асинхронных задач, подождать, когда они завершатся и обработать полученные результаты.

Вот пример:

private void acceptBoth() {
        final CompletableFuture<String> futureOne = CompletableFuture.supplyAsync(()-> {
            System.out.println("job one started");
            sleep(3);
            System.out.println("job one is done");
            return "feature done one";
        });
        final CompletableFuture<String> futureTwo = CompletableFuture.supplyAsync(()-> {
            System.out.println("job two started");
            sleep(7);
            System.out.println("job two is done");
            return "feature done two";
        });
        System.out.println("waiting...");
        futureOne.thenAcceptBothAsync(futureTwo,
                (result1, result2) -> System.out.println("join:" + result1 + " " + result2));
        System.out.println("end");
    }

Обратите внимание на структуру futureOne.thenAcceptBothAsync. Ждём, когда завершатся обе задачи, и обрабатываем итоговый результат. В отличие от предыдущих примеров, в этом фрагменте кода поток выполнения программы не ждёт, когда завершатся future, а идёт дальше.

Вывод:

CompletableFuture из пакета java.util.concurrent предоставляет полезный и простой в использовании функционал, который помогает ускорить разработку и упростить код. В то же время надо помнить, что в java.util.concurrent много тонких моментов, требующих понимания и некоторой сноровки в использовании.

Есть вопрос? Напишите в комментариях!

Автор
1 комментарий
0

Спасибо, хорошая шпаргалка по CompletableFuture. А зачем такие короткие заметки разбивать на 2 части?

Для комментирования необходимо авторизоваться