Zip operator
One more operator that we will look at is zip. This has a more complex behavior, as it combines values from two parallel streams by applying a zip function. It is often used for data enrichment, especially when parts of an expected result are retrieved from different sources, as shown in the following diagram:
Here, Netflix uses a zip operator to combine movie descriptions, movie posters, and movie ratings when streaming a list of recommended videos. However, for the sake of simplicity, let's zip just two streams of string values, as shown in the following code:
Observable.zip(
Observable.just("A", "B", "C"),
Observable.just("1", "2", "3"),
(x, y) -> x + y
).forEach(System.out::println);
The preceding code joins elements one by one from two streams, as depicted in the preceding diagram, and produces the following console output:
A1
B2
C3
To learn more about operators that are commonly used in reactive programming (not only in RxJava) visit http://rxmarbles.com. This site contains interactive diagrams that reflect actual operator behavior. In turn, the interactive UI allows us to visualize the events' transformation with regards to the order and time in which each event appeared in the streams. Note that the site itself is built with the RxJS library (see https://github.com/ReactiveX/rxjs for more details), which is RxJava's counterpart in the JavaScript world.
As previously mentioned, RxJava's Observable provides dozens of stream transformation operators that confidently cover a lot of use cases. Of course, RxJava does not only limit developers to operators provided by the library. One can also write a custom operator by implementing a class that is derived from the Observable.Transformer<T, R>. Such operator logic could be included in the workflow by applying the Observable.compose(transformer) operator. At the moment, we are not going to dive into the operator's building theory or practice; we are going to cover that in later chapters, partially. So far, it will be enough to highlight that RxJava provides a robust set of instruments for building complicated asynchronous workflows that are mainly limited by our imagination, not by the library.