Java Reference
In-Depth Information
Function.identity() and UnaryOperator.identity()
Perhaps the simplest to understand is
Function.identity()
. This provides a function that simply returns
its argument. It is very useful in testing, when you want to test something that takes a function and acts on
it. This can also be useful as a placeholder function: say that you have five types, and with four of them, you
want to perform some transformation; with the fifth, you don't want to perform a transformation. In that
case, you can maintain the symmetry of your codebase and avoid using
null
(and
NullPointerException
s)
by using this method.
10
This method is also available under the
UnaryOperator
type, so that you can keep
using that
Function
subclass and save yourself some typing.
Function.compose and Function.andThen
These two default methods provide the ability to take on functionality before and after a given function. The
methods allow you to create a pipeline effect in a rather fluent API, and are especially useful for converting
the types of a function to what you want them to be; you can prepend or append conversion functions inline.
If you want to change the result type, use
andThen
. Given the function
X->Y
,
andThen
allows you to
create
X->Z
by specifying a function that takes the result,
Y
, and produces a
Z
. The argument,
X
, will be fed to
the instance function, and then the results of the instance function,
Y
, are fed into the argument function.
As an example, consider this series of method calls:
Function<Integer,String> f = Integer::toString;
f = f.andThen("10"::concat).andThen(Integer::parseInt);
These will create a function that will turn an
int
into a
String
, and then prepend “10,” and then parse
the value back out into an
int
. What started as an
int->String
type is now an
int(->String->String)-
>int
, returned in Java types as an
int->int
.
If you want to change the argument type, use
compose
. This method should have been called
butFirst
,
because it works just like
andThen
, but on the front end instead of the back end. Given the function
X->Y
,
butFirst allows you to create
W->Y
by specifying a function that takes some
W
and produces an
X
. The result of
the specified function is fed as the argument to the instance function. We can specify the previous example
“backwards” by doing this:
Function<String,Integer> f = Integer::parseInt;
f = f.compose("10"::concat).compose(Integer::toString);
Consumer.andThen
The Java SDK does not provide a
Consumer.compose
to modify the accepted type,
11
but there is a
Consumer.andThen
. Since the consumer takes in an argument but produces no result, all that
andThen
does
is add additional processing; given two consumers of the same type, it provides a single consumer that
executes both the given consumers. This lets you add additional processing to the end of your stream of
processing. It is particularly useful for adding logging or other notifications into your consumer.
10
See “Don't Use Null” below.
11
See the FunJava project's
Functions
class: it provides a
compose
method that takes a
Function
and a
Consumer
and
provides a
Consumer
.