Java 8 CompletableFuture. Часть 1
Данная статья написана командой Vertex Academy. Это одна из статей из нашего Учебника по Java 8. Надеемся, что данная статья Вам будет полезна. Приятного прочтения!
В этой статье мы рассмотрим азы асинхронной обработки данных в Java 8 с помощью CompletableFuture.
1. Введение
CompletableFuture - новый класс для асинхронной работы, который дает возможность комбинировать шаги обработки, соединяя их в цепочку. Класс содержит около 50 методов для выполнения, объединения а так же обработки исключений. Рассмотрим мы лишь некоторые из них.
2. Простейший CompletableFuture
Для создания CompletableFuture можно воспользоваться методами supplyAsync()
1 |
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hi"); |
где future исполнится в ForkJoinPool.commonPool(), т.к. мы не указывали ему Executor. Если мы хотим указать где будет исполняться future то передаем Executor вторым параметром.
1 2 |
CompletableFuture<String> future = CompletableFuture .supplyAsync(() -> "Hi", Executors.newCachedThreadPool()); |
и runAsync()
1 |
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> System.out.println("Hi")); |
1 2 |
CompletableFuture<Void> future = CompletableFuture .runAsync(() -> System.out.println("Hi"), Executors.newCachedThreadPool()); |
Разница в том, что supplyAsync() принимает Supplier, а runAsync -> Runnable. Проще говоря, с помощью supplyAsync() можно вернуть результат, с runAsync() - нельзя.
3. Получение результата
Для того, чтобы получить результат с CompletableFuture необходимо вызвать метод get()
1 2 3 4 5 6 7 |
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(500); // имитируем долгое выполнение } catch (InterruptedException e) {} return "Hi"; }); System.out.println(future.get()); //output Hi |
Но стоит помнить, что вызов этого метода блокирующий, поток будет ждать пока CompletableFuture не вернет результат и о асинхронности можно забыть.
4. Добавление callback
Более приемлемым способом обработать результат работы CompletableFuture есть callback. Если после выполенения задачи мы хотим вывести ее на екран, это будет выглядеть так
1 2 3 4 5 |
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hi"); future.thenAccept(result -> System.out.println(result)); future.get(); |
get() вызывается для того, чтобы подождать исполнения future. Его можно заменить, к примеру, на Thread.sleep.
5. Добавление нескольких callback
Для добавления несколько callback метод thenAccept() не подоходит, поскольку Consumer ничего не возвращает. Для этого нужно использовать другой метод - thenApply(), который принимает Function.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hi"); future.thenApply(result -> { System.out.println(result + " all"); //output Hi all return result; }); future.thenApply(result -> { System.out.println(result + ", world!"); //output Hi, world! return result; }); future.get(); |
Нужно помнить, что функция в thenApply() исполняется в том же потоке, где вызывается. Если же использовать thenApplyAsync(), тогда функция будет исполнена как отдельная задача в ForkJoinPool.commonPool .
1 2 3 4 5 6 7 8 |
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hi"); future.thenApplyAsync(result -> { System.out.println(result + " all"); //output Hi all return result; }); Thread.sleep(100); |
Тут уже пришлось подождать пока функция выполнится в отдельном потоке и использовать Thread.sleep()
В следующей статье мы рассмотрим объединение CompletableFuture и обработку исключений.
В Java 8 есть еще множество полезных нововведений, которые можно найти тут
Надеемся - наша статья была Вам полезна. Есть возможность записаться на наши курсы по Java в Киеве. Детальную информацию смотрите у нас на сайте.