Java Functional Composition
Jakob Jenkov |
Functional composition is a technique to combine multiple functions into a single function which uses the combined functions internally. You can compose individual functions (typically one or more Java Lambda Expressions) into a single function yourself, but Java also comes with built-in support for functional composition to make the job easier for you. In this Java functional composition tutorial I will explain both how to compose functions from smaller functions yourself, and via Java's built-in features.
Java Functional Composition Example
To get started, let me show you an example of Java functional composition. Here is a single function composed from two other functions:
Predicate<String> startsWithA = (text) -> text.startsWith("A"); Predicate<String> endsWithX = (text) -> text.endsWith("x"); Predicate<String> startsWithAAndEndsWithX = (text) -> startsWithA.test(text) && endsWithX.test(text); String input = "A hardworking person must relax"; boolean result = startsWithAAndEndsWithX.test(input); System.out.println(result);
This functional composition example first creates two Predicate
implementations in the form
of two lambda expressions. The first Predicate
returns true
if the String
you pass to it as parameter starts with an uppercase a (A
). The second Predicate
returns true
if the String passed to it ends with a lowercase x . Note, that the
Predicate interface contains a single unimplemented
method named test()
which returns a boolean
. It is this method the lambda expressions implement.
After creating the two basic functions, a third Predicate
is composed, which calls the
test()
methods of the two first functions. This third function returns true
if
both of the basic functions return true
, and false
otherwise.
Finally, this example calls the composed function and prints out the result. Since the text both starts
with an uppercase a (A
) and ends with a lowercase x, the composed function will return
true
when called with the String "A hardworking person must relax
".
Java Functional Composition Support
The example in the previous section showed you how to compose a new function from two other functions.
Several of the functional interfaces in Java
already has support for functional composition built into them. The functional composition support comes in the
shape of default
and static
methods in the functional interfaces. For more
on default
and static
methods in interfaces, see my
Java Interfaces tutorial.
Predicate Composition
The Predicate
interface (java.util.function.Predicate
) contains a few methods that help
you compose new Predicate
instances from other Predicate
instances. I will cover some
of these methods in the following sections.
and()
The Predicate
and()
method is a default
method. The and()
method is used to combine two other Predicate
functions in the same way I showed in the beginning
of this Java functional composition tutorial. Here is an example of functional composition with the
Predicate
and()
method:
Predicate<String> startsWithA = (text) -> text.startsWith("A"); Predicate<String> endsWithX = (text) -> text.endsWith("x"); Predicate<String> composed = startsWithA.and(endsWithX); String input = "A hardworking person must relax"; boolean result = composed.test(input); System.out.println(result);
This Predicate
composition example composes a new Predicate
from two other
Predicate
instances using the and()
method of one of the basic Predicate
instances.
The composed Predicate
will return true
from it's test()
method if both of the Predicate
instances it was composed from also return true
.
In other words, if both Predicate
one and Predicate
two return true.
or()
The Predicate
or()
method is used to combine a Predicate
instance
with another, to compose a third Predicate
instance. The composed Predicate
will
return true
if either of the Predicate
instances it is composed from return true
,
when their test()
methods are called with same input parameter as the composed Predicate
.
Here is a Java Predicate
or()
functional composition example:
Predicate<String> startsWithA = (text) -> text.startsWith("A"); Predicate<String> endsWithX = (text) -> text.endsWith("x"); Predicate<String> composed = startsWithA.or(endsWithX); String input = "A hardworking person must relax sometimes"; boolean result = composed.test(input); System.out.println(result);
This Predicate
or()
functional composition example first creates two basic
Predicate
instances. Second, the example creates a third Predicate
composed
from the first two, by calling the or()
method on the first Predicate
and passing the second Predicate
as parameter to the or()
method.
The output of running the above example will be true
because the first of the two
Predicate
instances used in the composed Predicate
will return true
when called with the String "A hardworking person must relax sometimes
".
Function Composition
The Java Function
interface (java.util.function.Function
) also contains a few
methods that can be used to compose new Function
instances from existing ones. I will cover
some of these methods in the following sections.
compose()
The Java Function
compose()
method composes a new Function
instance from
the Function
instance it is called on, and the Function
instance passed as parameter
to the compose()
method.
The Function
returned by compose()
will first call the Function
passed
as parameter to compose()
, and then it will call the Function
which compose()
was called on. This is easier to understand with an example, so here is a Java Function
compose()
example:
Function<Integer, Integer> multiply = (value) -> value * 2; Function<Integer, Integer> add = (value) -> value + 3; Function<Integer, Integer> addThenMultiply = multiply.compose(add); Integer result1 = addThenMultiply.apply(3); System.out.println(result1);
When called with the value 3
, the composed Function
will first call the
add Function
and then the multiply Function
. The resulting calculation will
be (3 + 3) * 2
and the result will be 12.
andThen()
The Java Function
andThen()
method works opposite of the compose()
method.
A Function
composed with andThen()
will first call the Function
that andThen()
was called on, and then it will call the Function
passed as parameter
to the andThen()
method. Here is a Java Function
andThen()
example:
Function<Integer, Integer> multiply = (value) -> value * 2; Function<Integer, Integer> add = (value) -> value + 3; Function<Integer, Integer> multiplyThenAdd = multiply.andThen(add); Integer result2 = multiplyThenAdd.apply(3); System.out.println(result2);
This example first creates a multiply Function
and an add Function
. Then the
andThen()
method is called on the multiply Function
to compose a new Function
,
passing the add Function
as parameter to andThen()
.
Calling the Function
composed by andThen()
with the value 3 will result in the
following calculation
3 * 2 + 3
and the result will be 9.
Note: As mentioned in the beginning, andThen()
works opposite of compose()
.
Therefore, calling a.andThen(b)
is actually the same as calling b.compose(a)
.
Tweet | |
Jakob Jenkov |