Являются ли потоки Java 8 похожими на наблюдаемые RxJava?
Определение потока Java 8:
Классы в новом пакете
java.util.stream
предоставляют Stream API для поддерживать функциональные операции над потоками элементов.
Являются ли потоки Java 8 похожими на наблюдаемые RxJava?
Определение потока Java 8:
Классы в новом пакете
java.util.stream
предоставляют Stream API для поддерживать функциональные операции над потоками элементов.
TL; DR: все библиотеки обработки последовательности/потока предлагают очень похожий API для построения конвейера. Различия в API для обработки многопоточности и составления конвейеров.
RxJava довольно сильно отличается от Stream. Из всех JDK-объектов наиболее близким к rx.Observable является, возможно, java.util.stream.Collector Stream + CompletableFuture combo (которое обходится ценой работы с дополнительным монадным слоем, т.е. С обработкой преобразования между Stream<CompletableFuture<T>>
и CompletableFuture<Stream<T>>
).
Существуют значительные различия между Observable и Stream:
Stream#parallel()
разбивает последовательность на разделы, Observable#subscribeOn()
и Observable#observeOn()
- нет; сложно эмулировать поведение Stream#parallel()
.parallel()
с Observable, у него когда-то был .parallel()
но этот метод вызвал столько путаницы, что поддержка .parallel()
была перемещена в отдельный репозиторий на github, RxJavaParallel. Подробнее в другом ответе.Stream#parallel()
#rallel Stream#parallel()
не позволяет указывать пул потоков для использования, в отличие от большинства методов RxJava, принимающих необязательный планировщик. Поскольку все потоковые экземпляры в JVM используют один и тот же пул fork-join, добавление .parallel()
может случайно повлиять на поведение в другом модуле вашей программы.Observable#interval()
, Observable#window()
и многие другие; это в основном потому, что потоки на основе пулtakeWhile()
, takeUntil()
); Обходной путь с использованием Stream#anyMatch()
ограничен: это терминальная операция, поэтому вы не можете использовать его более одного раза для каждого потокаObservable#using()
); вы можете обернуть его потоком ввода-вывода или мьютексом и быть уверенным, что пользователь не забудет освободить ресурс - он будет автоматически удален при прекращении подписки; В Stream есть onClose(Runnable)
, но вы должны вызывать его вручную или с помощью try-with-resources. Например Вы должны иметь в виду, что Files # lines() должен быть заключен в блок try-with-resources.Сводка: RxJava значительно отличается от Streams. Реальные альтернативы RxJava - это другие реализации ReactiveStream, например, соответствующая часть Akka.
Обновление Есть хитрость в использовании нестандартного пула ветвления соединения для Stream#parallel
, см. Пул пользовательских потоков в параллельном потоке Java 8
Обновление Все вышеперечисленное основано на опыте работы с RxJava 1.x. Теперь, когда RxJava 2.x уже здесь, этот ответ может быть устаревшим.
Java 8 Stream и RxJava выглядит довольно похоже. Они имеют похожие операторы (фильтр, карта, flatMap...), но не созданы для одного и того же использования.
Вы можете выполнять задачи asynchonus с помощью RxJava.
С потоком Java 8 вы перемещаете элементы своей коллекции.
Вы можете сделать почти то же самое в RxJava (элементы трассировки коллекции), но, поскольку RxJava сосредоточен на параллельной задаче,..., он использует синхронизацию, защелку... Так что одна и та же задача с использованием RxJava может быть медленнее, чем с потоком Java 8.
RxJava можно сравнить с CompletableFuture
, но это может вычислить не только одно значение.
Существует несколько технических и концептуальных различий, например, потоки Java 8 - однопользовательские, основанные на тяге, синхронные последовательности значений, тогда как RxJava Observables являются повторно наблюдаемыми, адаптивно основанными на push-pull, потенциально асинхронными последовательностями значений. RxJava нацелен на Java 6+ и работает на Android.
Java 8 Streams основаны на pull. Вы перебираете поток Java 8, потребляющий каждый элемент. И это может быть бесконечный поток.
RXJava Observable
по умолчанию основан на нажатии. Вы подписываетесь на Наблюдаемый, и вы получите уведомление, когда придет следующий товар (onNext
), или когда поток будет завершен (onCompleted
), или когда произошла ошибка (onError
).
Поскольку с Observable
вы получаете события onNext
, onCompleted
, onError
, вы можете выполнять некоторые мощные функции, такие как объединение разных Observable
в новый (zip
, merge
, concat
). Другие вещи, которые вы могли бы сделать, это кеширование, дросселирование,...
И он использует более или менее тот же API на разных языках (RxJava, RX в С#, RxJS,...)
По умолчанию RxJava является однопоточным. Если вы не начнете использовать Планировщики, все будет происходить в одном потоке.
Существующие ответы являются исчерпывающими и правильными, но для начинающих отсутствует четкий пример. Позвольте мне поставить некоторые конкретные термины, такие как "push/pull-based" и "re-observable". Примечание: я ненавижу термин Observable
(это поток ради бога), поэтому просто буду ссылаться на потоки J8 против RX.
Рассмотрим список целых чисел,
digits = [1,2,3,4,5]
J8 Stream - это утилита для изменения коллекции. Например, даже цифры могут быть извлечены как,
evens = digits.stream().filter(x -> x%2).collect(Collectors.toList())
Это в основном карта Python , фильтр, сокращение, очень хорошее (и давно назревшее) дополнение к Java. Но что, если цифры не были собраны раньше времени - что, если цифры были переданы во время работы приложения - мы могли бы отфильтровать их даже в режиме реального времени.
Представьте, что отдельный процесс потока выводит целые числа в случайное время, пока приложение работает (---
обозначает время)
digits = 12345---6------7--8--9-10--------11--12
В RX even
может реагировать на каждую новую цифру и применять фильтр в режиме реального времени
even = -2-4-----6---------8----10------------12
Там нет необходимости хранить входные и выходные списки. Если вам нужен выходной список, нет проблем, которые тоже можно стримировать. На самом деле все это поток.
evens_stored = even.collect()
Вот почему такие термины, как "без состояний" и "функционал", больше связаны с RX
RxJava также тесно связан с инициатива реактивных потоков и рассматривает ее как простую реализацию API реактивных потоков (например, по сравнению с реализация потоков Akka). Основное отличие состоит в том, что реактивные потоки предназначены для обработки обратного давления, но если вы посмотрите на страницу реактивных потоков, вы получите эту идею. Они довольно хорошо описывают свои цели, а потоки также тесно связаны с реактивным манифестом.
В потоках Java 8 реализована неограниченная коллекция, очень похожая на Scala Stream или Clojure lazy seq.
Java 8 Streams позволяют эффективно обрабатывать действительно большие коллекции, одновременно используя многоядерные архитектуры. Напротив, RxJava по умолчанию имеет однопоточность (без планировщиков). Таким образом, RxJava не будет использовать многоядерные машины, если вы сами не закодируете эту логику.