Functional Programming in Java 8 with vavr

We’re very happy to announce a guest post on the jOOQ Blog written by Daniel Dietrich, Senior Software Engineer at HSH Nordbank, husband and father of three. He currently creates a pricing framework for financial products as project lead and lead developer. Daniel Dietrich Besides his work, he is interested in programming languages, efficient algorithms and data structures. Daniel wrote the short book Play Framework Starter on building web-applications with the Play Framework for Java and Scala – and has been creating vavr, a functional component library for Java 8 recently, which has triggered our interest in particular.
It was a really exciting moment as I heard that Java will get lambdas. The fundamental idea of using functions as a means of abstraction has its origin in the ‘lambda calculus’, 80 years ago. Now, Java developers are able to pass behavior using functions.

List<Integer> list = Arrays.asList(2, 3, 1);

// passing the comparator as lambda expression
Collections.sort(list, (i1, i2) -> i1 - i2);

Lambda expressions reduce the verbosity of Java a lot. The new Stream API closes the gap between lambdas and the Java collection library. Taking a closer look shows, that parallel Streams are used rarely or at least with caution. A Stream cannot be reused and it is annoying that collections have to be converted forth and back.

// stream a list, sort it and collect results
Arrays.asList(2, 3, 1)
  .stream()
  .sorted()
  .collect(Collectors.toList());
        
// a little bit shorter
Stream.of(2, 3, 1)
  .sorted()
  .collect(Collectors.toList());

// or better use an IntStream?
IntStream.of(2, 3, 1)
  .sorted()
  .collect(ArrayList::new, List::add, List::addAll);

// slightly simplified
IntStream.of(2, 3, 1)
  .sorted()
  .boxed()
  .collect(Collectors.toList());

Wow! These are quite some variants for sorting a list of integers. Generally we want to focus on the what rather than wrapping our heads around the how. This extra dimension of complexity isn’t necessary. Here is how to achieve the same result with vavr:

List.of(2, 3, 1).sort();

〜 Typically every object oriented language has an imperative core, so does Java. We control the flow of our applications using conditional statements and loops.

String getContent(String location) throws IOException {
    try {
        final URL url = new URL(location);
        if (!"http".equals(url.getProtocol())) {
            throw new UnsupportedOperationException(
                "Protocol is not http");
        }
        final URLConnection con = url.openConnection();
        final InputStream in = con.getInputStream();
        return readAndClose(in);
    } catch(Exception x) {
        throw new IOException(
            "Error loading location " + location, x);
    }
}

Functional languages have expressions instead of statements, we think in values. Lambda expressions help us transforming values. Here is one example, using vavrps Try:

Try<String> getContent(String location) {
    return Try
        .of(() -> new URL(location))
        .filter(url -> "http".equals(url.getProtocol()))
        .flatMap(url -> Try.of(url::openConnection))
        .flatMap(con -> Try.of(con::getInputStream))
        .map(this::readAndClose);
}

The result is either a Success containing the content or a Failure containing an exception. In general, this notion is more concise compared to the imperative style and leads to robust programs we are able to reason about. 〜 I hope this brief introduction has peaked your interest in vavr! Please visit the site to learn more about functional programming with Java 8 and vavr.

16 thoughts on “Functional Programming in Java 8 with vavr

  1. Very nice library! I’m gonna use it for sure! Some api are a little bit weird tough, for instance the one for Pattern Matching: Match.caze.orElse?!? I understand it had to follow the standard naming, but Match.when.otherwise it would have been much better! :)

  2. Thanks for the feedback!

    I’m aligning the syntax with Scala for the language constructs Java doesn’t have (yet). Scala has `x match case …`. Also Haskell’s pattern matching has `case`.

    You find the `orElse()` in other places of the Javaslang library for alternative return values, e.g. Either, Option and Try have it. The name is based on `java.util.Optional.orElse()`, so developers don’t have to remember other names for the same thing.

    1. Yep I got that and I generally agree with you, in such situations it is better to have a coesive and standardized API, but sometimes I prefer to have streight-forward naming w/o too much camel case and conflits with the reserved words :)

      it’s just a matter of taste, nothing else I think. However I really like your library! It would be amazing if it was compatible with Java7 at least, with Retrolambda and some Google Guava I think it’s possible to achive the same results (well I dunno your library very well at the moment, just assuming).

  3. Yes, I fixed that weired name `caze`: https://github.com/javaslang/javaslang/pull/226

    Guava is designed to be a toolset of missing types and extensions to existing Java types. It is superior in simplifying daily tasks, like apache commons.

    Javaslang goes beyond that – it introduces new concepts and focuses on functional programming (immutability, all is an expression, composability, …). It has a consistent type system, the classes are designed to play well together. E.g. a `Match` expression and the collections `List` and `Stream` are also of type `Function` and can be used where a function of that type is required.

    It’s the little things in programming which make life so much easier…

    It should be possible to port Javaslang with Retrolambda to Java 7. Volunteers? ;-)

    1. You can copy what I did with FunctionalJava to keep that compatible with Java 7. When I next take a look at Javaslang, which parts should I look at that would be additions to FunctionalJava?

  4. Hi Mark,

    thank you, I really appreciate that! I’m a little bit in doubt that all features are back-portable, e.g. for the Match API I currently use some Java 8 specific features (lambda serialization). I don’t know if older JVM’s are capable to do so.

    Javaslang is tailored to bring functional programming to object oriented Java developers. FunctionalJava is maintained by well-known Scala/Scalaz devs in order to bring pure functional and compositional programming to Java. It is highly influenced by Haskell and has a high level of abstraction. My impression is that there is an imbalance between level of abstraction and practicability in FunctionalJava. Java is verbose, common functional features are missing, like for- and list-comprehensions, higher-kinded types, etc. This makes Java applications ‘encoded’ in FunctionalJava a little bit cryptic, but that is only my own impression.

    With Javaslang, I can make design decision from the practical perspective, which enable me to design better APIs. An example is the type ‘Kind’ (http://bit.ly/1JSH2k4), which models semi-higher-order types. Given this type, we are able to provide methods within a class hierarchy, we are not able to declare with plain Java. FunctionalJava goes another way, you duplicate code instead I think, which is also a viable solution I took into consideration for Javaslang.

    So, coming back to your question, I think that Javaslang and FunctionalJava are both great on its own. I don’t try to compare them or search distinct features, the other library does not have. If you want to theoretically reason about your programs, I recommend FunctionalJava.

    Respectfully,

    Daniel

  5. Hi Chris,

    thank you for your question – and this is a really interesting one! I’m afraid, at the moment I can’t come up with concrete numbers. But I have a relative clear picture of what we would expect at runtime.

    This morning, on a walk to the coffee-automaton, I talked with a collegue about the benefits of C++ over Java. Java’s strength is that it is secure in terms of memory management. But with C++ we have more freedom. It is easy to write C++ programs that go terribly wrong. But if you do it the right way, it will be of great good. The point is, it will eventually go wrong.

    The Try monad internally uses try-catch. On top of it there are additional objects created, a Success/Failure instance holding the result and a Supplier for deferring the computation, two objects per try call. Subsequent method calls may need more resources.

    I think we can roughly compare it with auto-boxing/unboxing of primitive values. It takes place everywhere – and yes, there is a performance impact, GC will run more frequently. Try (and similar types) are literally used everywhere in other JVM languages, like Scala. It is proven, tested and I highly suggest to use it to make your code more robust. Beware of premature optimization!

    However, object creation (and GC) is the Achilles’ heel of Java. If there is a piece of code that needs to run fast and with a low memory profile, then I would first profile the application, identify bottlenecks and then optimize. In many cases the cpu & mem consumers are hidden in places we don’t expect them at a first glance.

    Coming back to your question of metrics I think it is very hard to create a real-world use-case. Compared to auto boxing/unboxing I can easily box/unbox one million elements and prove that it is a constant factor slower than using just primitive values. But this is not what happens in production systems all the time. It depends on the application.

    – Daniel

    1. @danieldietrich, @chrisjasonkelly

      The Try monad internally uses try-catch

      Only when wrapping existing Java methods though, right? Throwing Exceptions is expensive because of capture of the stack trace (in fillInStackTrace method in the Exception – overriding this and removing the StackTrace capture signifcantly improves the speed of standard Try/ Catch in Java).

      If you use Try as a functional replacement for throwing Exceptions (as in return Failure.of(new MyFastException() / Success.of(result)) rather than as a referential transparency breaking goto statement / or continuation – you *can* get much better performance with Try than with traditional Try / Catch in Java.

      Note, I say can, because you still need to override fillInStackTrace on your custom fast exceptions as the Constructor for Throwable is :

      public Throwable() {
              fillInStackTrace();
      }
      

      I don’t think you need the stacktrace with Try as it is simply a normal Object passed back as any other through your call stack (i.e. it’s easily traceable, because it can’t jump around crazily a lá standard throw new Exception()).

      1. Hi John, this is a great idea but also risky. Imagine an exception thrown by a 3rd party lib. Removing the whole stack trace will make it impossible to track down errors/bugs. Also the fillInStackTrace-trick is orthogonal to the type of exception handling, i.e. it should also work with try/catch without using Try, right?

        1. Hi Daniel, with the technique above you should never throw the exceptions (which would cause all the problems you describe & break referential transparency), you are just using the Exceptions to represent the fail side of the Try.

          It may be less confusing to developers maintaining the code to use an Either and store the failure case in something other than an Exception. It’s effectively the same solution and more performant (in the failure case) than throwing an exception.

          I’m not advocating that people routinely create custom exceptions if it leads to confusion or maintainability problems for their teams. Just pointing out that there are performance optimizations available for many situations when using libraries like Javaslang.

          1. Hi John, thank you for clarification. I thought about it the last days and think Java exception handling indeed needs a renewal. Your proposal is great. I need to play around with it by time!

  6. There a difference between the 2 versions of the last example:
    Imperative

    if (!"http".equals(url.getProtocol())) {
                throw new UnsupportedOperationException(
                    "Protocol is not http");
    }
    

    Functional version does not throw an exception when the theme is http.
    I’m curious how to do that using javaslang

  7. Hi pgehl, you are absolutely right. The current 2.1.0-alpha of Javaslang has Try.filter() methods that allow us to additionally specify an exception supplier.

    The following functional code should be equivalent to the first example:

    Try getContent(String location) {
        return Try
            .of(() -> new URL(location))
            .filter(url -> "http".equals(url.getProtocol()),
                    () -> { new UnsupportedOperationException("Protocol is not http"); })
            .flatMap(url -> Try.of(url::openConnection))
            .flatMap(con -> Try.of(con::getInputStream))
            .map(this::readAndClose);
    }
    

    By default Try.filter(predicates) produces a Failure(NoSuchElementException(“Predicate does not hold for ” + value)) in the empty case.

    I think there was no concise way to do it with Javaslang 1.0.

Leave a Reply