Java Joy: Composing Functions
In Java we can write single argument functions that implement the java.util.function.Function
interface. We can combine multiple functions into a new function using the andThen
and compose
methods from the Function
interface. We need to give another function as argument to these methods. When we use the andThen
method the output of the original function will be input of the function passed as argument. With the compose
method our function will get as input the output of the function that is passed as argument. It is important to know the difference, because it can change the result of the function we are composing. The andThen
and compose
methods are also available on the IntUnaryOperator
, LongUnaryOperator
and DoubleUnaryOperator
interface.
In the following example we use both andThen
and compose
to chain together some functions. We can see the result can be different when using andThen
and compose
with the same functions.
package com.mrhaki.sample;
import java.util.Map;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import java.util.function.UnaryOperator;
public class Compose {
public static void main(String[] args) {
// Two simple functions that take a int argument
// and do some calculations.
IntUnaryOperator f = x -> 11 + (x - 90);
IntUnaryOperator g = x -> x * 2;
// Using andThen will first execute f and use
// the result as input for g:
// (11 + (100 - 90)) * 2
assert 42 == f.andThen(g).applyAsInt(100);
// Using compose will first execute g and use
// the result as input for f:
// 11 + ((100 * 2) - 90)
assert 121 == f.compose(g).applyAsInt(100);
// Map with some user data.
var user =
Map.of("name", "Hubert",
"alias", "MrHaki");
// Function to duplicate a String.
UnaryOperator<String> duplicate = s -> String.format("%1$s,%1$s", s);
// Function to turn String into lowercase.
UnaryOperator<String> lowerCase = String::toLowerCase;
// Function with Map parameter to create a new function with
// a String parameter that will get the
// value for a given key from the map that is passed.
Function<Map<String, String>, UnaryOperator<String>> getFromMap =
map -> key -> map.get(key);
// Chain using andThen.
Function<String, String> andThenUserKey =
getFromMap.apply(user)
.andThen(lowerCase)
.andThen(duplicate);
assert "mrhaki,mrhaki".equals(andThenUserKey.apply("alias"));
// Chain using compose.
Function<String, String> composeUserKey =
duplicate.compose(lowerCase)
.compose(getFromMap.apply(user));
assert "mrhaki,mrhaki".equals(composeUserKey.apply("alias"));
}
}
Written with Java 15.