Function Composition in Java
One can argue that composing functions is the most important idea in programming and functional programming in particular. The idea of compositionality is of monumental importance in human thinking. Creating systems by composing smaller systems that are easier to implement and design can be found in all levels of programming. Staring from the Syntax of the language, to Design patterns, architectural patterns, larger System design etc.
In this section we are going to take a brief look at one of the most basic ones; Function composition.
In mathematics, function composition is the application of one function to the result of another to produce a third function. For instance, the functions f : T→ R and g : R→ U can be composed to yield a function h: g(f(x)) which maps T→ U we usually represent that as g ○ f and we read that as “g after f ” the symbol ○ usually represents “after”.
Programmatically for the functional interfaces there are two ways called
.compose() to make this composition. If you have a
Function<T, R> you can:
- Either post-compose
.andThen(Function<R, U>)another function
- Or you can start with
Function<R, U>and pre-compose compose
Now we are now going to take a brief look at the most common java util Functional interface
Since the most usual functional interface is
Function<T, R> it provides a default method .andThen (docs.oracle) that takes another
Function<R, U> and returns a
run this : Fiddle
we can write the composition in the opposite direction using the compose method
BiFunction<U, V, R> also provides an
Take a look at the following function composition :
Run This: Fiddle
The Consumer and Supplier do not provide any composition methods build in, but is easy to imagine even visually a supplier post-compose method :
We can create an extension for that :
Which we can use like this :
SupplierFunctor<Integer> d = () -> 5;SupplierFunctor<Integer> f = d.andThen(x -> x + 5);
Run This: Fiddle
All the .andThen methods for Functional interfaces are the same as our good old familiar
Stream.map(). With a lot of imagination, you can think of
()->5 as a Stream or Array with a single element.
Excerpt from the book: