Асинхронный CompletableFuture. Часть 2 | OTUS
⚡ Подписка на курсы OTUS!
Интенсивная прокачка навыков для IT-специалистов!
Подробнее

Курсы

Программирование
Python Developer. Professional
-3%
Разработчик на Spring Framework
-5%
iOS Developer. Professional
-8%
Golang Developer. Professional
-6%
Базы данных
-12%
Agile Project Manager
-5%
Android Developer. Professional
-11%
Microservice Architecture
-5%
C++ Developer. Professional
-5%
Highload Architect
-6%
JavaScript Developer. Basic
-8%
Kotlin Backend Developer
-9%
C# Developer. Professional
-9%
Team Lead
-6%
Алгоритмы и структуры данных Разработчик программных роботов (RPA) на базе UiPath и PIX Unity Game Developer. Basic Разработчик голосовых ассистентов и чат-ботов Vue.js разработчик VOIP инженер NoSQL Супер-практикум по использованию и настройке GIT Symfony Framework iOS Developer. Basic Супер-интенсив «СУБД в высоконагруженных системах» Супер-интенсив "Tarantool"
Инфраструктура
DevOps практики и инструменты
-12%
Базы данных
-12%
Network engineer. Basic
-10%
Network engineer
-4%
Экcпресс-курс «ELK»
-10%
Инфраструктурная платформа на основе Kubernetes
-6%
Administrator Linux.Basic
-10%
Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes»
-30%
Дизайн сетей ЦОД
-13%
PostgreSQL
-8%
Разработчик программных роботов (RPA) на базе UiPath и PIX Reverse-Engineering. Professional Внедрение и работа в DevSecOps Administrator Linux. Advanced Infrastructure as a code in Ansible Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes Экспресс-курс «IaC Ansible»
Специализации Курсы в разработке Подготовительные курсы
+7 499 938-92-02

Асинхронный 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 много тонких моментов, требующих понимания и некоторой сноровки в использовании.

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

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

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

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

Для комментирования необходимо авторизоваться
🔥 Только до 28.02
Успейте приобрести курсы февраля на выгодных условиях! Подробности в чате.