January 23, 2021

Learn RxJava with Emacs Org mode

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!

Powered by Hugo & Kiss.