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

Курсы

Программирование
Java Developer. Professional Highload Architect C++ Developer. Basic Специализация C++ Developer C++ Developer. Professional Java Developer. Basic Kotlin Developer. Basic Microservice Architecture JavaScript Developer. Basic Cloud Solution Architecture Team Lead C# Developer. Professional Алгоритмы и структуры данных Rust Developer C# Developer. Basic NoSQL Выбор профессии в IT
-99%
Python Developer. Basic Python Developer. Professional Базы данных iOS Developer. Professional React.js Developer Scala-разработчик Специализация iOS Unity Game Developer. Basic Руководитель разработки Разработчик Android Последние изменения в Java AWS для разработчиков Разработчик программных роботов (RPA) на базе UiPath и PIX NOSQL CI/CD Kotlin Backend Developer Node.js Developer Специализация Java и Архитектор ПО Специализация PHP и Базы Данных Интенсив «Оптимизация в Java» Супер - интенсив по паттернам проектирования Теория Игр Супер - интенсив по Kubernetes Symfony Framework Advanced Fullstack JavaScript developer Супер-интенсив "Tarantool" Spring Framework для Diasoft Специализация PHP Developer PostgreSQL Cloud Solutions Golang Developer Буткемп Python Developer Angular Developer
Специализация Java-разработчик JavaScript Developer. Professional Android Developer. Professional Программист С HTML/CSS Специализация Fullstack developer Android Developer. Basic Специализация Android-разработчик Software Architect PostgreSQL для администраторов баз данных и разработчиков PHP Developer. Professional Web-разработчик на Python Agile Project Manager Unity Game Developer. Professional C# Developer Flutter Mobile Developer Разработчик на Spring Framework Специализация Python Developer Golang Developer. Professional Unreal Engine Game Developer. Basic Архитектура и шаблоны проектирования C# ASP.NET Core разработчик iOS Developer. Basic Computer Science VR/AR - разработчик Разработчик Java Enterprise MS SQL Server Developer Framework Laravel PostgreSQL Специализация Java-разработчик (консультации) Разработчик чат-ботов и приложений для виртуальных ассистентов Анализ данных и машинное обучение в MATLAB Vue.js разработчик VOIP инженер Специализация Java и Базы данных Специализацияz PHP Fullstack разработчик Программист 1С Разработчик децентрализованных систем Супер-практикум по использованию и настройке GIT Разработчик IoT Подготовка к сертификации Oracle Java Programmer (OCAJP) Супер-интенсив «СУБД в высоконагруженных системах» Супер-интенсив Azure PHP Developer. Basic Буткемп Java Groovy Developer C# Developer Буткемп Frontend Developer
Инфраструктура
Highload Architect Дизайн сетей ЦОД DevOps 1C Microservice Architecture Software Architect Cloud Solution Architecture Внедрение и работа в DevSecOps Administrator Linux. Advanced DevOps практики и инструменты Network Security MS SQL Server Developer Oracle DBA Безопасность Linux PostgreSQL NOSQL CI/CD Супер-практикум по работе с протоколом BGP Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes Супер-интенсив «СУБД в высоконагруженных системах» Супер-интенсив "SQL для анализа данных" Экспресс-курс по управлению миграциями (DBVC) Экспресс-курс «Введение в непрерывную поставку на базе Docker» Специализация Network Engineer MongoDB AWS Cloud Developer
Корпоративные курсы
Machine Learning. Professional Spark Developer Дизайн сетей ЦОД Java QA Engineer. Basic Cloud Solution Architecture Пентест. Практика тестирования на проникновение Внедрение и работа в DevSecOps Выбор профессии в IT
-99%
DevOps практики и инструменты MLOps Game QA Engineer Цифровая подпись в ИБ Машинное обучение для обеспечения ИБ Компьютерная криминалистика (форензика) Безопасность компьютерных сетей Пентестинг мобильных приложений Руководитель ИБ Безопасность Linux Разработчик программных роботов (RPA) на базе UiPath и PIX Анализ данных и машинное обучение в MATLAB Практикум по Kali Linux Node.js Developer Супер-практикум по работе с протоколом BGP Интенсив «Оптимизация в Java» Программист 1С Супер - интенсив по паттернам проектирования Супер-практикум по использованию и настройке GIT Разработчик IoT Embedded-разработчик Экспресс-курс по управлению миграциями (DBVC) Экспресс-курс "Версионирование и командная работа с помощью Git" Супер-интенсив Azure Интенсив AWS Data Engineer MongoDB b2b-webinar
Agile Project Manager Компьютерное зрение Руководитель поддержки пользователей в IT Reverse-Engineering Системный аналитик. Advanced NoSQL Системный аналитик. Basic Экспресс-курс «IaC Ansible» IT-Recruiter Enterprise Architect Экcпресс-курс «ELK» Пентест веб-приложений Разработчик блокчейн-проектов Безопасность приложений Криптографическая защита информации Безопасность информационных систем SRE практики и инструменты Защита персональных данных в корпоративных системах Разработчик чат-ботов и приложений для виртуальных ассистентов CTF по ИБ Специализация Реверс & Пентест VOIP инженер Супер-интенсив «Data Engineer» Infrastructure as a code Безопасность веб-приложений Теория Игр Супер - интенсив по Kubernetes Revit Супер-интенсив "SQL для анализа данных" Экспресс-курс «CI/CD» Экспресс-курс «Введение в непрерывную поставку на базе Docker» BPMN: Моделирование бизнес-процессов Основы Windows Server Вебинар CERTIPORT Python для аналитики
Специализации Курсы в разработке Подготовительные курсы Подписка
+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 части?

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