Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Monadic futures in Java 8: How to organize your data flow and avoid callback hell

Prepare to Java 8: async computations, futures, monads, oh my!

Few people will argue that asynchronous computation is cool and useful. In fact, the whole reactive programming idea is based on asynchronous computations being possible. Well, there’s more than that, but the core idea is to allow data and events to flow through your system and do something with the results when they become available.

So let’s look at an example of asynchronous function that everyone has seen and many have written themselves.

$("#book").fadeIn("slow", 
  function() {
   console.log(“hurray”);
  });

This piece of JavaScript code takes a book element and fades it in. When fading is complete a callback function is called and “hurray” string appears in the console. All is well and good in this trivial case, but once your system grows you can find yourself writing more and more of these nested callbacks.

Callbacks are a common way of dealing with asynchronous or delayed actions. They are not the best option though; the problem with callbacks is that they tend to chain forever, callbacks for callbacks for callbacks, until you find yourself in a complete mess and every change in the code becomes extremely painful and slow.

Maybe there are other ways to organize asynchronous code? In fact, there are: all you need to do is just tweak the perspective a bit. Imagine, if you had a type to represent a result of an async computation. It would be awesome, and your code would pass it around like every other value and be flat, fluid and readable.

Well, why don’t we build it!

When we’re done, we’ll have a monadic type Promise written in Java 8 that will make our asynchronous code wonderful. It’s not like it wasn’t ever done before, but I want to lead you through the process and help you understand what’s happening and why. If you are lazy or just prefer starting from code, check out the github repo.

Getting to love monads in 9.5 minutes

Oh, monads! Every programmer worth their morning coffee has written about them. Monads are what functional programming adepts love, use and praise. And there are thousands of tutorials and posts describing the concept.

So if you know everything there is to know about monads and want to get a closer look onto more interesting things, scroll down to the code below. Otherwise, bear with me just ten minutes, maybe this will become your go-to explanation about what a monad is.

A monad is a type, that represents a context of computation. I bet you’ve heard that before, but have you thought about what it means?

First of all, a monad doesn’t specify what is happening, that’s the responsibility of the computation within the context. A monad says what surrounds the computation that is happening.

Now, if you want an image reference to help you out, you can think of a monad as a bubble. Some people prefer a box, but a box is something concrete so a bubble works better for me.
A lovely bubble with a cure dragon-ish creature inside
These monad-bubbles have two properties:

  • a bubble can surround something
  • a bubble can receive instructions about what should it do with a surrounded thing

The surrounding part is easy to model in a programming language. Just take something and return a bubble! A constructor or a factory method comes to mind immediately here. Let’s look at how it is formalized. I’m assuming that you have some knowledge of Haskell notation (which you probably should have anyway). So the function that takes something and returns a monad is usually called pure or return:

return :: a -> m a

Or in Java, if we can have some Monad class already.

public class Monad<T> { 
  public Monad(T t) {}
}

See that was easy. In fact, we’re halfway there. Another thing we must add is the ability to receive instructions for working with this value T eaten by our bubble.

What will help us is a bind function, which takes some form of an action and returns a different monad bubble that wraps this action executed on whatever was previously in the bubble.

For the sake of completeness, here is how it looks in Haskell.

(>>=)  :: m a -> (a -> m b) -> m b

So this bind function takes a monad over a, (m a) and a function from a, and returns a different monad. In Java, we’ll have this definition as follows.

public class Monad<T> { 
  public abstract <V> Monad<V> bind(Function<T, Monad<V>> f);
}

That will complete our generic definition of monads so we can proceed with an implementation.

Wait, what? I can have my monads in Java?

First of all, there are many different types of monads. In that sense, a monad is more like an interface in Java terms. There is a List monad, a Maybe monad, an IO monad (for languages that are very pure and cannot allow themselves to have normal IO), etc.

We will focus on creating a specific monad in Java, more specifically in Java 8. There is a good reason as to why we chose Java 8, since previously we found out that a monad will have to manipulate functions, which is really not that enjoyable in pre-lambda versions of Java.  However, Java 8 introduces lambdas and first-class methods, so it will be much more pleasant to work with them.

Your homemade Promise implementation

Here we go, now we’ve established our goal to have a monadic type to represent async computations. We’ve got our tools, namely Java 8, and we are ready to hack.

What we want to have is a Promise class that represents a result of asynchronous computation, either successful or erroneous.

Let’s pretend that we already have some Promise class that accepts callbacks to execute when the main computation is finished. Luckily, we don’t have to pretend very much, there are many implementations of that available: Akka’s Future, Play’s promise and so forth.

For this post I’m using the one from Play Framework, in which case instances of Promise get redeemed when some thread calls invoke() or invokeWithException() methods. It also accepts callbacks in a form of Play’s Promise specific Action class arguments. Obviously, Promise has constructors already, but not only do I want to create new instances of Promise, I also want to mark them completed with a value immediately. Here is how I can do it.

public static <V> Promise<V> pure(final V v) {
    Promise<V> p = new Promise<>();
    p.invoke(v);
    return p;
  }

The returned Promise is already redeemed and is ready to provide us with a result of the computation, which is precisely the given value.

The bind implementation will look like something below. It takes a function and adds that as a callback to this instance. A callback will get a result of this computation and apply given function to it. Whatever that function application returns or throws is used to redeem the resulting Promise.

public <R> Promise<R> bind(final Function<V, Promise<R>> function) {
    Promise<R> result = new Promise<>();
 
    this.onRedeem(callback -> {
      try {
        V v = callback.get();
        Promise<R> applicationResult = function.apply(v);
        applicationResult.onRedeem(applicationCallback -> {
          try {
            R r = applicationCallback.get();
            result.invoke(r);
          }
          catch (Throwable e) {
            result.invokeWithException(e);
          }
        });
      }
      catch (Throwable e) {
        result.invokeWithException(e);
      }
    });
    return result;
  }

Both applying the given function and getting a result from this are wrapped into the try-catch blocks, so exceptions are propagated to the resulting instance of Promise, just as one might expect.

With these two constructs, it’s very easy to chain asynchronous computations while avoiding going deeper and deeper into the callback hell. In the following synthetic example, we do exactly that.

public static void example1() 
                    throws ExecutionException, InterruptedException {
    Promise<String> promise = Async.submit(() -> {
      String helloWorld = "hello world";
      long n = 500;
      System.out.println("Sleeping " + n + " ms example1");
      Thread.sleep(n);
      return helloWorld;
    });
    Promise<Integer> promise2 = promise.bind(string ->
              Promise.pure(Integer.valueOf(string.hashCode())));
    System.out.println("Main thread example2");
    int hashCode = promise2.get();
    System.out.println("HashCode = " + hashCode);
  }

That is basically it. We’ve implemented a monadic type Promise to represent a result of an async action.

Production-ready completable future

For those of you who have beared with me this far, I just want to say some final words about the quality of this implementation. Naturally, the above-mentioned GitHub repository has some tests that are proving that in some contexts, this might all work. However, I wouldn’t recommend using those Promises in production.

One reason for that is that Java 8 already contains a class that represents a result of async computation and is monadic…, welcome, CompletableFuture!

It does exactly what we want it to do and features several methods that allow you to bind a function to the result of an existing computation. Moreover, it provides methods to apply a function or a consumer, which is a void function by the way, or a plain old Runnable.

On top of that, methods that end on *Async will execute this function asynchronously using a common ForkJoin executor. Otherwise, you can also supply an executor of your own liking.

Conclusion

Hopefully, this post shed some light onto what a monad is and next time you are about write a callback, you might want to consider a different approach.

In the post above we’ve looked at what monads are and how one can implement monadic classes in Java 8. Monads are great help in organizing data flow through your code and we’ve shown it with an example of Promise monad that represents results of an asynchronous computation. All the code from this blogpost is available for pondering in the Github repo.

Stay tuned for my next post, in which I plan to cover how to use the javaflow library to implement asynchronous awaiting for the promise to return a result. So you can get even more reactive :-)


Want to learn more about what rocks in Java 8? Check out Java 8 Revealed: Lambdas, Default methods and Bulk Data Operations by Anton Arhipov

Get the PDF