Learning Reactive Programming With Java 8 - Sample Chapter
Learning Reactive Programming With Java 8 - Sample Chapter
ee
Nickolay Tsvetinov
P U B L I S H I N G
pl
C o m m u n i t y
$ 44.99 US
29.99 UK
Learning Reactive
Programming with Java 8
Sa
m
E x p e r i e n c e
D i s t i l l e d
Learning Reactive
Programming with Java 8
Learn how to use RxJava and its reactive Observables to build
fast, concurrent, and powerful applications through detailed
examples
Nickolay Tsvetinov
Preface
Reactive programming has been around for decades. There has been a few
implementations of reactive programming from the time Smalltalk was a young
language. However, it has only become popular recently and it is now becoming a
trend. Why now you ask? Because it is good for writing fast, real-time applications
and current technologies and the Web demand this.
I got involved in it back in 2008, when the team I was part of was developing a
multimedia book creator called Sophie 2. It had to be fast and responsive so we
created a framework called Prolib, which provided objects with properties which
could depend on each other (in other words, we implemented bindings for Swing
and much moretransformations, filtering, and so on). It felt natural to wire the
model data to the GUI like this.
Of course, this was far away from the functional-like approach that comes with RX.
In 2010, Microsoft released RX and, after that, Netflix ported it to JavaRxJava.
However, Netflix released RxJava to the open source community and the project
became a huge success. Many other languages have their port of RX and many
alternatives to it. Now, you can code using reactive programming on your Java
backend and wire it to your RxJava's frontend.
This book tries to explain to you what reactive programming is all about and how
to use it with RxJava. It has many small examples and it explains concepts and API
details in small steps. After reading this book, you will have an idea of RxJava,
functional programming, and the reactive paradigm.
Preface
An Introduction to Reactive
Programming
Nowadays, the term reactive programming is trending. Libraries and frameworks in
various programming languages are emerging. Blog posts, articles and presentations
about reactive programming are being created. Big companies, such as Facebook,
SoundCloud, Microsoft, and Netflix, are supporting and using this concept. So we,
as programmers, are starting to wonder about it. Why are people so excited about
reactive programming? What does it mean to be reactive? Would it be helpful in our
projects? Should we learn how to use it?
Meanwhile, Java is popular with its multi-threading, speed, reliability, and good
portability. It is used for building a wide variety of applications, from search engines,
through databases to complex web applications running on server clusters. But
Java has bad reputation tooit is very hard to write both concurrent and simple
applications using only the built-in tools, and programming in Java requires writing
a lot of boilerplate code. Also, if you need to be asynchronous (using futures, for
example), you can easily get into "callback hell", which actually holds true for all
programming languages.
In other words, Java is powerful and you can create great applications with it, but it
won't be easy. The good news is that there is a way to change that, using the reactive
style of programming.
This book will present RxJava (https://github.com/ReactiveX/RxJava), an open
source Java implementation of the reactive programming paradigm. Writing code
using RxJava requires a different kind of thinking, but it will give you the power to
create complex logic using simple pieces of well-structured code.
[1]
[2]
Chapter 1
This is a very simple explanation of what "being reactive" means. Of course, there
are various implementations of this idea and there are various problems that these
implementations must solve.
Scalable: This way, we are going to be able to handle a huge amount of data
or large numbers of user requests.
Fault-tolerant: This way, the system will appear stable to its users.
Responsive
Resilient
Scalable
Event-Driven
[4]
Chapter 1
Introducing RxJava
To write reactive programs, we need a library or a specific programming language,
because building something like that ourselves is quite a difficult task. Java is not
really a reactive programming language (it provides some tools like the java.util.
Observable class, but they are quite limited). It is a statically typed, object-oriented
language, and we write a lot of boilerplate code to accomplish simple things (POJOs,
for example). But there are reactive libraries in Java that we can use. In this book,
we will be using RxJava (developed by people in the Java open source community,
guided by Netflix).
Of course, you can also download the prebuilt JAR. For this book, we'll be using
version 1.0.8.
If you use Maven, you can add RxJava as a dependency to your pom.xml file:
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava</artifactId>
<version>1.0.8</version>
</dependency>
Alternatively, for Apache Ivy, put this snippet in your Ivy file's dependencies:
<dependency org="io.reactivex" name="rxjava" rev="1.0.8" />
If you use Gradle instead, update your build.gradle file's dependencies as follows:
dependencies {
...
compile 'io.reactivex:rxjava:1.0.8'
...
}
[5]
Now, let's take a peek at what RxJava is all about. We are going to begin with
something well known, and gradually get into the library's secrets.
[6]
Chapter 1
4. The first five times, when we call the next() method on the Iterator
instance, it will return the elements in the order they were inserted in the
collection. So the strings will be printed.
In this example, our program consumes the items from the List instance using the
Iterator instance. It pulls the data (here, represented by strings) and the current
thread blocks until the requested data is ready and received. So, for example, if the
Iterator instance was firing a request to a web server on every next() method
call, the main thread of our program would be blocked while waiting for each of the
responses to arrive.
RxJava's building blocks are the observables. The Observable class (note that this is
not the java.util.Observable class that comes with the JDK) is the mathematical
dual of the Iterator class, which basically means that they are like the two sides of
the same coin. It has an underlying collection or computation that produces values
that can be consumed by a consumer. But the difference is that the consumer doesn't
"pull" these values from the producer like in the Iterator pattern. It is exactly the
opposite; the producer 'pushes' the values as notifications to the consumer.
Here is an example of the same program but written using an Observable instance:
List<String> list = Arrays.asList("One", "Two", "Three", "Four",
"Five"); // (1)
Observable<String> observable = Observable.from(list); // (2)
observable.subscribe(new Action1<String>() { // (3)
@Override
public void call(String element) {
System.out.println(element); // Prints the element (4)
}
});
[7]
The ability to signal the consumer that there is no more data available.
Instead of calling the hasNext() method, we can attach a subscriber to listen
for a 'OnCompleted' notification.
The ability to signal the subscriber that an error has occurred. Instead of trycatching an error, we can attach an error listener to the Observable instance.
Chapter 1
new Action0() {
@Override
public void call() {
System.out.println("We've finnished!"); // (2)
}
});
We saw how we can use the Observable instances and that they are not so different
from something familiar to usthe Iterator instance. These Observable instances
can be used for building asynchronous streams and pushing data updates to their
subscribers (they can have multiple subscribers).This is an implementation of the
reactive programming paradigm. The data is being propagated to all the interested
partiesthe subscribers.
Coding using such streams is a more functional-like implementation of Reactive
Programming. Of course, there are formal definitions and complex terms for it,
but this is the simplest explanation.
Subscribing to events should be familiar; for example, clicking on a button in a
GUI application fires an event which is propagated to the subscribershandlers.
But, using RxJava, we can create data streams from anythingfile input, sockets,
responses, variables, caches, user inputs, and so on. On top of that, consumers can be
notified that the stream is closed, or that there has been an error. So, by using these
streams, our applications can react to failure.
[9]
When both the a and b collectors have initial values, their sum will
automatically be computed and printed on the standard output in the format
a + b = <sum>. On every change in a or b, the sum will be updated and
printed.
The source code contains features that we will discuss in detail in the next four
chapters.
The first piece of code represents the main body of the program:
ConnectableObservable<String> input = from(System.in); // (1)
Observable<Double> a = varStream("a", input); (2)
Observable<Double> b = varStream("b", input);
ReactiveSum sum = new ReactiveSum(a, b); (3)
input.connect(); (4)
[ 10 ]
Chapter 1
Chapter 1
8. If the program reaches here (through breaking out of the main loop) and the
subscriber is still subscribed to the Observable instance, an OnCompleted
notification is sent to the subscribers using the onCompleted() method.
9. With the publish() method, we turn the new Observable instance into
ConnectableObservable instance. We have to do this because, otherwise,
for every subscription to this Observable instance, our logic will be executed
from the beginning. In our case, we want to execute it only once and all the
subscribers to receive the same notifications; this is achievable with the use
of a ConnectableObservable instance. Read more about that in Chapter 3,
Creating and Connecting Observables, Observers, and Subjects.
This illustrates a simplified way to turn Java's IO streams into Observable instances.
Of course, with this main loop, the main thread of the program will block waiting
for user input. This can be prevented using the right Scheduler instances to move
the logic to another thread. We'll revisit this topic in Chapter 6, Using Concurrency
and Parallelism with Schedulers.
Now, every line the user types into the terminal is propagated as a notification by
the ConnectableObservable instance created by this method. The time has come to
look at how we connect our value Observable instances, representing the collectors
of the sum, to this input Observable instance. Here is the implementation of the
varStream(String, Observable) method, which takes a name of a value and source
Observable instance and returns an Observable instance representing this value:
public static Observable<Double> varStream(final String varName,
Observable<String> input) {
final Pattern pattern = Pattern.compile("\\^s*" + varName +
"\\s*[:|=]\\s*(-?\\d+\\.?\\d*)$"); // (1)
return input
.map(new Func1<String, Matcher>() {
public Matcher call(String str) {
return pattern.matcher(str); // (2)
}
})
.filter(new Func1<Matcher, Boolean>() {
public Boolean call(Matcher matcher) {
return matcher.matches() && matcher.group(1) != null; //
(3)
}
})
.map(new Func1<Matcher, Double>() {
public Double call(Matcher matcher) {
return Double.parseDouble(matcher.group(1)); // (4)
[ 13 ]
The map() and filter() methods called on the Observable instance here are part
of the fluent API provided by RxJava. They can be called on an Observable instance,
creating a new Observable instance that depends on these methods and that
transforms or filters the incoming data. Using these methods the right way, you can
express complex logic in a series of steps leading to your objective. Read more about
this in Chapter 4, Transforming, Filtering, and Accumulating Your Data. Let's analyze the
code:
1. Our variables are interested only in messages in the format <var_name>:
<value> or <var_name> = <value>, so we are going to use this regular
expression to filter and process only these kinds of messages. Remember that
our input Observable instance sends each line the user writes; it is our job to
handle it the right way.
2. Using the messages we receive from the input, we create a Matcher instance
using the preceding regular expression as a pattern.
3. We pass through only data that matches the regular expression. Everything
else is discarded.
4. Here, the value to set is extracted as a Double number value.
This is how the values a and b are represented by streams of double values, changing
in time. Now we can implement their sum. We implemented it as a class that
implements the Observer interface, because I wanted to show you another way of
subscribing to Observable instancesusing the Observer interface. Here is the code:
public static final class ReactiveSum implements Observer<Double>
{ // (1)
private double sum;
public ReactiveSum(Observable<Double> a, Observable<Double> b) {
this.sum = 0;
Observable.combineLatest(a, b, new Func2<Double, Double,
Double>() { // (5)
public Double call(Double a, Double b) {
return a + b;
}
}).subscribe(this); // (6)
}
public void onCompleted() {
System.out.println("Exiting last sum was : " + this.sum); //
(4)
[ 14 ]
Chapter 1
}
public void onError(Throwable e) {
System.err.println("Got an error!"); // (3)
e.printStackTrace();
}
public void onNext(Double sum) {
this.sum = sum;
System.out.println("update : a + b = " + sum); // (2)
}
}
This is the implementation of the actual sum, dependent on the two Observable
instances representing its collectors:
1. It is an Observer interface. The Observer instance can be passed to the
Observable instance's subscribe(Observer) method and defines three
methods that are named after the three types of notification: onNext(T),
onError(Throwable), and onCompleted. Read more about this interface in
Chapter 3, Creating and Connecting Observables, Observers, and Subjects.
2. In our onNext(Double) method implementation, we set the sum to the
incoming value and print an update to the standard output.
3. If we get an error, we just print it.
4. When everything is done, we greet the user with the final sum.
5. We implement the sum with the combineLatest(Observable,
Observable, Func2) method. This method creates a new Observable
instance. The new Observable instance is updated when any of the two
Observable instances, passed to combineLatest receives an update. The
value emitted through the new Observable instance is computed by the
third parametera function that has access to the latest values of the two
source sequences. In our case, we sum up the values. There will be no
notification until both of the Observable instances passed to the method
emit at least one value. So, we will have the sum only when both a and b
have notifications. Read more about this method and other combiners in
Chapter 5, Combinators, Conditionals, and Error Handling.
6. We subscribe our Observer instance to the combined Observable instance.
Here is sample of what the output of this example would look like:
Reacitve Sum. Type 'a: <number>' and 'b: <number>' to try it.
a:4
b:5
update : a + b = 9.0
[ 15 ]
So this is it! We have implemented our reactive sum using streams of data.
The source code of this example can be downloaded and tried out from
here: https://github.com/meddle0x53/learning-rxjava/
blob/master/src/main/java/com/packtpub/reactive/
chapter01/ReactiveSumV1.java.
Summary
In this chapter, we went through the reactive principles and the reasons we
should learn and use them. It is not so hard to build a reactive application; it just
requires structuring the program in little declarative steps. With RxJava, this can be
accomplished by building multiple asynchronous streams connected the right way,
transforming the data all the way through its consumer.
The two examples presented in this chapter may look a bit complex and confusing
at first glance, but in reality, they are pretty simple. There are a lot of new things in
them, but everything will be explained in detail in the following chapters.
If you want to read more about reactive programming, take a look at Reactive
Programming in the Netflix API with RxJava, a fine article on the topic, available at
http://techblog.netflix.com/2013/02/rxjava-netflix-api.html. Another
fine post introducing the concept can be found here: https://gist.github.com/
staltz/868e7e9bc2a7b8c1f754.
And these are slides about reactive programming and RX by Ben Christensen, one
of the creators of RxJava: https://speakerdeck.com/benjchristensen/
reactive-programming-with-rx-at-qconsf-2014.
In the next chapter, we are going to talk about some of the concepts of functional
programming and their implementation in Java 8. This will give us the basic ideas
needed in the rest of the chapters and will help us get rid of Java verbosity when
writing reactive programs.
[ 16 ]
www.PacktPub.com
Stay Connected: