Java: Method Reference composition

Introduction

Since JDK 8 there is the java.util.function package responsible to abstract everything that has to do with functions. Most of the time you will find yourself creating your own functions but sometimes, if you’re aware of method references you will find out that many of those functions you were about to create were already in the jdk, or at least you will be able to use function composition to create new ones.

Silly example

Lets say we would like to sum two numbers and then add ten to the result and finally return the result as a String. Ok a first naive implementation would be:

public static String doStuff(Integer a, Integer b) {
    Integer sumResult = a + b + 10;

    return sumResult.toString();
}

It’s just horrible, everything mixed up, we cannot reuse anything. Although we can create a lambda expression to represent a sum, there’s no need for that. You can use the Integer::sum method reference that can exactly do that. The problem is that you can’t do something like:

// THIS WON'T COMPILE
(Integer::sum).andThen((Integer a) -> a + 10).andThen(Object::toString);

But the solution is very close. We can create a pair of utility functions receiving a Function or a BiFunction to "catch" the method reference and use it like any of these type of functions. Here are the utility functions:

/**
 * Utility function to convert a method reference to a
 * {@link Function}
 *
 * @param fn method reference matching a {@link Function}
 * @return the matching {@link Function}
 */
public static <A,B> Function<A,B> use(Function<A,B> fn) {
    return fn;
}

/**
 * Utility function to convert a method reference to a
 * {@link BiFunction}
 *
 * @param fn method reference matching a {@link BiFunction}
 * @return the matching {@link BiFunction}
 */
public static <A,B,C> BiFunction<A,B,C> use(BiFunction<A,B,C> fn) {
    return fn;
}

And then you can, for example, compose functions with andThen flavor:

public static String doMoreStuff(Integer a, Integer b) {
    BiFunction<Integer,Integer,String> fn = use(Integer::sum)
        .andThen(x -> x + 10)
        .andThen(Object::toString);

    return fn.apply(a,b);
}
andThen seems to be more familiar to imperative programmers because it follows a logical path: first this, and then that, and then that…​. It describes a sequence of events.

Or using compose flavor:

public static String doEvenMoreStuff(Integer a, Integer b) {
    Function<Integer,String> extras =
        use(Object::toString).compose((Integer x) -> x + 10); (1)

    BiFunction<Integer,Integer,String> fn =
        use(Integer::sum).andThen(extras); (2)

    return fn.apply(a,b);
}
1 Composing functions using compose
2 Applying previous composed functions after the result of the sum function
compose is the type of composition you could find in languages as Haskell where the composition evaluation is read from right to left (first function is the one in the right hand side).