CompletableFuture vs Future: асинхронность с новыми функциями Java 8
Java 8 была выпущена в марте 2014 года и получила длинный список новых функций. Одна из наименее обсуждаемых, чрезвычайно полезных, но неправильно понятых функций — это совершенно новое и улучшенное расширение интерфейса Future: CompletableFuture <T>.
В следующем посте мы представим общее представление о CompletableFuture, как именно оно отличается от простого Future и когда оно может быть полезным.
Асинхронный код Java
Java 7 познакомила нас с Future, который представляет собой результат асинхронных вычислений. Основным преимуществом использования объекта Future является то, что вы можете делать другие вещи, ожидая внешних ресурсов. Неблокирующий способ ожидания ресурса.
Использование Future означает, что вы можете написать метод и вместо того, чтобы немедленно возвращать результат, он вернет объект Future. Когда вам понадобится фактический результат, просто используйте Future.get (), который вернет значение после завершения вычислений.
Вы также получаете методы для проверки того, выполнено ли вычисление, и способ отменить / проверить, было ли оно отменено.
Например, предположим, что вы делаете вызов некоторому внешнему ресурсу, например … API разработчика Marvel , вытаскивая всех супергероев, которые имеют букву … «C» в своем имени:
1
2
3
4
5
6
7
8
9
|
Future < String > marvel = executor.submit( new Callable < String > () { public String call() { return getMarvelHeroWithCharacter(“C”); // totally not making this up } }); // other very important stuff of course, non-blocking ftw System.out.println(marvel.get()); // this bit is blocking if the result isn’t ready yet |
Да, если мы хотим использовать полностью асинхронную неблокирующую опцию, нам не повезло. У нас нет уверенности в том, что будущее действительно существует, и нам, возможно, придется подождать. Вот тут-то и приходит CompletableFuture и помогает с нахальным обходным путем.
Так что же нового в CompletableFuture?
CompletableFuture <T> расширяет Future <T> и делает его… завершаемым. Это большое дело, учитывая, что объекты Future были ограничены до Java 8, только с 5 доступными методами.
Это новое и улучшенное CompletableFuture имеет 2 основных преимущества:
- Это может быть явно завершено путем вызова метода complete () без какого-либо синхронного ожидания. Это позволяет в будущем получать значения любого типа с возвращаемыми значениями по умолчанию, даже если вычисление не было завершено, с использованием результатов по умолчанию / промежуточных результатов.
- Благодаря десяткам новых методов, он также позволяет вам построить процесс передачи данных в виде последовательности действий. Вы можете найти несколько шаблонов для CompletableFutures, таких как создание CompletableFuture из задачи или создание цепочки CompletableFuture. Полный список доступен в документации Oracle CompletableFuture .
Возвращаясь к нашему простому примеру, допустим, что API Marvel не вернул своевременный результат, и getMarvelHeroWithCharacter () все еще обрабатывает, тратит время, в то время как мы уже закончили со всем остальным, что мы хотели сделать за это время. Предполагая, что мы не хотим ждать ( чтобы наша жизнь закончилась ), CompletableFuture может помочь нам вернуть промежуточный результат. Как … Мистика, так как в худшем случае она может превратиться в любого другого супергероя.
01
02
03
04
05
06
07
08
09
10
11
|
CompletableFuture < String > marvel = executor.submit( new Callable < String > () { public String call() { return getMarvelHeroWithCharacter(“C”); } }); // other stuff goes here marvel.complete(“Mystique”); // sets a “default” value if not yet completed System.out.println(marvel.get()); // non-blocking |
Вы также можете заранее создать завершенное CompletableFuture, которое возвращает известное значение. Это может пригодиться в вашей среде тестирования , если вы захотите объединить это известное значение с тем, которое нужно вычислить:
1
2
3
4
|
CompletableFuture < String > cf = CompletableFuture.completedFuture( "I'm done!" ); cf.isDone(); // return true cf.join(); // return "I'm done" |
Доступны десятки других, более полезных методов, которые включают преобразование и действие в одном CompletableFuture (thenApply), выполнение кода при завершении (thenAccept / thenRun), объединение двух CompletableFuture вместе и многое другое. Для полного руководства мы рекомендуем прочитать Java 8: Полное руководство по CompletableFuture .
Познакомьтесь с альтернативами
Если вы используете Guava или Scala (с его Futures ), эта новая функция может показаться вам знакомой. Это похоже на ListenableFuture Guava, который определяет согласованный API для объектов Future для регистрации обратных вызовов завершения.
Подобно новому CompletableFuture, возможность добавлять обратный вызов позволяет отвечать на входящие события асинхронно и эффективно. Вы можете зарегистрировать обратные вызовы, которые будут выполняться после завершения вычислений, и поддерживать множество операций, которые не может поддерживать базовый интерфейс Future.
Когда прижмет
Использование CompletableFuture дает нам возможность работать вместе с нашим кодом, не дожидаясь результатов, но он по-прежнему не может обещать, что ваш код не сломается во время работы в производственной среде. При возникновении ошибок необходимо как можно быстрее выявлять и анализировать их, чтобы развернуть исправление.
В подобных ситуациях Takipi позволит вам эффективно устранять проблемы в коде, когда они возникают, без необходимости «ждать», пока кто-то еще не столкнется с ними.
Последние мысли
CompletableFuture вписывается в тенденцию асинхронного программирования, которая стала популярной в последние несколько лет. Неудивительно, что все говорят об этом, поскольку мы можем использовать его для одновременного выполнения ряда задач, что обеспечивает оптимальный рабочий процесс.
Если вы уже являетесь поклонником асинхронного программирования, вы можете проверить наш пост о 7 инструментах реактивного программирования, которые вы ДОЛЖНЫ знать .
Ссылка: | Назад к CompletableFuture: Основные возможности Java 8 от нашего партнера JCG Хенна Идана в блоге Takipi . |