Composing Functions – Functional-Style Programming

Composing Functions

Both the default methods compose() and andThen() of the Function<T, R> interface return an instance of a Function that is created from the caller function (i.e., the function on which the method is invoked) and the argument function (i.e., the function that is passed as an argument to the method). The two methods differ in the order in which they apply the caller and the argument functions. Given two functions f and g, the compose() and the andThen() methods execute as follows:

Click here to view code image

f.compose(g).apply(x)
emulates
 f.apply(g.apply(x))
or mathematically
 f(g(x)).
f.andThen(g).apply(x)
emulates
 g.apply(f.apply(x))
or mathematically
 g(f(x)).
f.compose(g).apply(x)
and
 g.andThen(f).apply(x)
are equivalent
.

The compose() method executes the argument function g first and executes the caller function f last. The andThen() method does the converse: It executes the caller function f first and executes the argument function g last. Switching the caller and the argument functions of one method in the other method gives the same result. Since the result of one function is passed as an argument to the other function, the return type of the function executed first must be compatible with the parameter type of the function executed last.

Creating compound functions with the default methods compose() and andThen() is illustrated by the code in Example 13.6. Functions f and g are defined at (1) and (2), respectively. The output from the program shows that the compose() method at (3) executes the function g first and the function f last—the same as the andThen() method at (4) with the functions switched and the explicit application at (5). The andThen() method at (6) executes the function f first and the function g last—the same as the compose() method at (7) with the functions switched and the explicit application at (8). The return type of the function executed first is also compatible with the parameter type of the function executed last—which is String for the functions f and g.

Click here to view code image

Function<String, String> f = s -> s + “-One”;    // (1)
Function<String, String> g = s -> s + “-Two”;    // (2)
System.out.println(f.compose(g).apply(“Three”)); // (3) Three-Two-One
System.out.println(g.andThen(f).apply(“Three”)); // (4) Three-Two-One
System.out.println(f.apply(g.apply(“Three”)));   // (5) Three-Two-One
System.out.println(f.andThen(g).apply(“Three”)); // (6) Three-One-Two
System.out.println(g.compose(f).apply(“Three”)); // (7) Three-One-Two
System.out.println(g.apply(f.apply(“Three”)));   // (8) Three-One-Two

Click here to view code image

default <V> Function<V,R> compose(Function<? super V,? extends T> before)

This generic method returns a composed function that first applies the before function to its input, and then applies this function to the result. (This function refers to the function used to invoke the method.)

Given that the type of this function is T -> R and the type of the argument function before is V -> T, the compose() method creates a compound function of type V -> R, as the function before is executed first and this function last.

Click here to view code image

default <V> Function<T,V> andThen(Function<? super R,? extends V> after)

This generic method returns a composed function that first applies this function to its input, and then applies the after function to the result.

Given that the type of this function is T -> R and the type of the argument function after is R -> V, the andThen() method creates a compound function of type T -> V, as this function is executed first and the function after last.

Any exception thrown during the evaluation of either function aborts the evaluation of the composed function and the exception is conveyed to the caller.

Leave a Comment