Intro
RxJava is a Java library that can be used to create non blocking reactive systems in Java. The mindset of non blocking and how to work with RxJava was a bit hard for me to grasp, and still is! I am by no means a skilled RxJava user. But I have found a tool that helps me on the journey to become a better one. And of course this is Org mode and Emacs.
If you know Org mode then most info in this post wont be anything new. What could be new to you is the new features that ob-java provides. Features that removes some of the boilerplate of the verbose language and you can focus on the important concepts.
If you are new to Org mode, take a look at my posts about "Emacs Orgmode Source Code Blocks" if you wanna know more about Org modes and source code blocks.
Setup
Document properties
This is properties that is used for all of the source code blocks in the
document. The properties states that we want all of our result output in code
blocks. All files and commands will be use the src/
directory. And set
classpaths and imports for RxJava so the compiler and executor know where to
find them.
#+PROPERTY: header-args :dir src :results output code :wrap example text
#+PROPERTY: header-args:java :cmdline -classpath .:src:./rxjava-1.3.8.jar :cmpflag -classpath .:src:./rxjava-1.3.8.jar :imports rx.Observable
Dependency and folder hierarchy.
This is the structure of the important files. We have the Org document in a
root. In the root is a directory named src/
and inside src/
is the RxJava
lib. You can find the RxJava lib here.
.
├── learn-rx-java.org # This is the Org file we are in
├── src # Folder where source code will live
│ ├── rxjava-1.3.8.jar # Here is the RxJava lib
Lets test it out
This is a minimal example of learn-rx-java.org
. What we see is a Java
source code block without all if the usually needed setup code, like public
static void main
. And we can focus on the RxJava operator just
. Below the
Java code there is a result block. That's the result of the Java code after
using C-c C-c
while standing on the source code block. Pretty neat!
#+PROPERTY: header-args :dir src :results output code :wrap example text
#+PROPERTY: header-args:java :cmdline -classpath .:src:./rxjava-1.3.8.jar :cmpflag -classpath .:src:./rxjava-1.3.8.jar :imports rx.Observable
#+BEGIN_SRC java
Observable.just("Hey from Org mode").subscribe(System.out::println);
#+END_SRC
#+RESULTS:
#+begin_example text
Hey from Org mode
#+end_example
But how!? Java needs all the fluff code to run, right? Of course it does! But the new features of Org modes ob-java takes care of that for us. So lets look at what happened.
It created two new files for us. Main.java
and Main.class
.
.
├── learn-rx-java.org
├── src
│ ├── Main.class
│ ├── Main.java
│ └── rxjava-1.3.8.jar
And if we look into the Main.java
file we can see the file that Org mode
created for us before running it through javac
.
And voila! We see that the import from the file property rx.Observable
is
there together with all the rest that is needed to run a Java program.
ob-java
have added the needed stuff for us so we don't need to think about.
I think that's terrific when learning!
import rx.Observable;
public class Main {
public static void main(String[] args) {
Observable.just("Hey from Org mode").subscribe(System.out::println);
}
}
The commands that ob-java executed looks something like this:
javac -classpath .:src:./rxjava-1.3.8.jar /home/john/git/blog/src/Main.java
&& java -cp /home/john/git/blog/src/ -classpath .:src:./rxjava-1.3.8.jar Main
This is the setup and how stuff works, let's try out some operators.
Operators
Here are some operators and how they can be used. The weight is on showing how Org mode can be used to learn the operators and not on the operators them self.
range
Useful when you wanna generate ranges.
This example is just as small as the just
in the setup section. It shows a
very basic usage of the range
operator.
#+BEGIN_SRC java
Observable.range(5, 3).subscribe(System.out::println);
#+END_SRC
#+RESULTS:
#+begin_example text
5
6
7
#+end_example
flatMapIterable
Useful when you have a collection/stream and you wanna turn each item into a observable.
This example is a little bit bigger and use a operation composition to transform a list.
#+BEGIN_SRC java
List<String> list = Arrays.asList("India", "China", "Bhutan");
System.out.println("Before: " +list);
Observable.just(list)
.flatMapIterable(x -> x)
.flatMap(s -> Observable.just(s.toLowerCase()))
.map(s -> "#-#" + s + "#-#")
.toList()
.subscribe(s -> { System.out.println("After: " + s);});
#+END_SRC
#+RESULTS:
#+begin_example text
Before: [India, China, Bhutan]
After: [#-#india#-#, #-#china#-#, #-#bhutan#-#]
#+end_example
flatMap
If you end up in a situation where one Observable returns another Observable.
For example like this: Observable<Observable<String>>
. Then flatMap
can
be handy (remember that flatMap don't preserve order!). This is how execution
could look like without it.
The inner Observable is never executed. It only returns a Observable object in some memory location.
#+BEGIN_SRC java
import static rx.Observable.just;
just(just("Hejsan")).subscribe(System.out::println);
#+END_SRC
#+RESULTS:
#+begin_example text
rx.internal.util.ScalarSynchronousObservable@30946e09
#+end_example
But when adding flatMap
to the composition the inner Observable is
executed.
#+BEGIN_SRC java
import static rx.Observable.just;
static Observable<Observable<String>> myText() {
return just(just("Hejsan"));
}
public static void main(String[] args) {
myText()
.flatMap(x -> x)
.subscribe(System.out::println);
}
#+END_SRC
#+RESULTS:
#+begin_example text
Hejsan
#+end_example
Here we needed to provide some more context for ob-java
to make it
understand our code.
zip
… is handy when you wanna combine results from Observables.
This example is little bit bigger and we have a inner class within our
ZipExample
class. In this scenario we provide a fully working Java class
where ob-java
don't need to do any changes to our code. It compiles,
executes the code and provide us with the result.
#+BEGIN_SRC java :results output code
import java.util.concurrent.TimeUnit;
import static rx.Observable.*;
public class ZipExample {
private static class Tenant {
public static Observable<Long> getTenantId(){
// Simulate network latency
return just(456123L).delay(1, TimeUnit.SECONDS);
}
public static Observable<String> getTenantName(){
// Simulate network latency
return just("myCamelCompany").delay(2, TimeUnit.SECONDS);
}
}
public static void main(String[] args) throws InterruptedException {
Observable<String> tenantName = Tenant.getTenantName();
Observable<Long> tenantId = Tenant.getTenantId();
zip(tenantName, tenantId, (name, id) -> {
return name + " / " + id;
}).subscribe(System.out::println);
System.out.println("Let's go!");
TimeUnit.SECONDS.sleep(3); // Dont quit just yet!
}
}
#+END_SRC
#+RESULTS:
#+begin_example text
Let's go!
myCamelCompany / 456123
#+end_example
Conclusion
This post shows how to write and execute RxJava where the focus is on the operators and not on all of the Java language fluff. I think it does a good job. In the later operations the examples grow and we needed to do some Java stuff. But in the smaller examples we can really focus on the operators.
I have used Org mode for interacting with languages from AWK to Python and Clojure. I am very happy to see that it works so good also for Java. Org mode is a wonderful tool!