04 - Function Composition

Function composition is the ability to create simple and reusable functions that can be combined in order to create more complex functions. Java made this easy

In the programming world, the process of function composition is also known as currying in honour of Haskell Brooks Curry, an American mathematician well known for his work in the combinatory logic field.

Although the words “combinatory logic” are enough to deliver us a panic attack, Java actually made this an easy process. Let’s see how it works.

The Function interface has two methods that allow us to compose functions. The andThen and compose methods.

Let’s take a quick look to the Function interface source code from the java.util.function

java.util.function.Function.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}

static <T> Function<T, T> identity() {
return t -> t;
}
}

I have to be honest, the first time I saw the signature of andThen() and compose() methods, I had to go back and read this a few times. If you feel like I did, well, just take a peek to the article to refresh your Generics.

The andThen() method is combining the current function with another function named after. But this is done in a way that the first function is applied and the input type T is converted to type R. After that the after function is applied and converts the type R to type V.

In simpler words the andThen() method applies both functions and also converts the type T to type V.

The compose() method is quite similar in the away it works, however it inverts the order of how the functions are applied.

Let’s see a quick example.(please note that I’m not using streams, because this series is about lambda expressions and the objective is to train our brain in creating functions, even if they look weird :) .

app.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class App {
static Function<List<Integer>, List<Integer>> doubleNumbersFunc;
static Function<List<Integer>, List<Integer>> squareNumbersFunc;
static Function<List<Integer>, List<Integer>> composedFunctionWithAndThen;
static Function<List<Integer>, List<Integer>> composedFunctionWithCompose;

static {// first static block
doubleNumbersFunc = numbers -> {
List<Integer> rethey aresult = new ArrayList<>();
for (Integer i : numbers) {
result.add(i * 2);
}
return result;
};
}

static {// Second static block
squareNumbersFunc = numbers -> {
List<Integer> result = new ArrayList<>();
for (Integer i : numbers) {
result.add(i * i);
}
return result;
};
}

static {//third static block
composedFunctionWithAndThen=doubleNumbersFunc.andThen(squareNumbersFunc);
composedFunctionWithCompose=doubleNumbersFunc.compose(squareNumbersFunc);
}

public static void main(String[] args) {

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

System.out.println("AndThen Result :" + composedFunctionWithAndThen.apply(list));

System.out.println("Compose Result :" + composedFunctionWithCompose.apply(list));
}
}

when run, this code prints

AndThen Result :[4, 16, 100, 324]
Compose Result :[2, 8, 50, 162]

So what is happening ?

First the functions are initialized in static blocks.

In the first static block we define the function doubleNumbersFunc. It receives a list of Integers, multiplies each value by 2 and returns a list with the result.

In the first static block we define the function squareNumbersFunc. It receives a list of Integers, squares each number and returns a list with the result.

The third block is the fancy one. We create the composed functions composedFunctionWithAndThen using the andThen() method and the composedFunctionWithCompose using the compose() method.

in the main method, we print the apply() of each of the combined functions.

As you can see, the result is different. This happens because andThen() applies the functions from left to right and compose() applies the functions from right to left.

in the above example this is how the andThen() worked,

and this is how the compose() worked,

The process is very straightforward, but we need extra care if we start assembling functions with nested andThen() and compose().

The last one in the Function interface is the identity(). This method’s mission is very simple. It just returns back the parameter which it gets as input. Usually the use of identity() is not to modify a value that has arrived to a function, and its usefulness becomes more obvious when used in conjunction with the java.util.stream.api.

In the next post I will look into another Functional interface. The Predicate. Don’t get upset. It’s only the programmers jargon for something that evaluate if a condition is true or false.

‘till then happy coding.

Share