Java Reference
In-Depth Information
Consuming Our Temp File Function
In a purely functional world, there is always a return value: a program is simply a function that takes the
string arguments and system environment variables as input and produces an exit code as output. However,
in a postfunctional language such as Java 8, we often want to use side effects instead of return values. This is
why the Consumer class is useful. Unfortunately, the API that we have provided so far only accepts functions,
which means that the user always has to specify a return value. Furthermore, when you take a reference to a
method with one argument but returning void, you get an instance of the Consumer interface. If we want to
allow users to pass in methods with that shape, we need to accept the Consumer interface.
This isn't too tricky, but it does require a bit of finagling. Of course, we want to build off of our existing
APIs instead of duplicating functionality. This means that we will need some bridge from the Consumer that
our user passes into the Function that our API desires. The difference between Consumer and Function is the
return value: Consumer returns void while Function returns a value. For our bridge, we will return a default
value. We could return null , but null is the evil path to NullPointerException . The other default non-value
is Optional.empty() , so we can use that. The resulting code looks like Listing 4-4.
Listing 4-4. Bridge from a Consumer to a Function
/**
* Convert a consumer to a function that consumes the argument and returns
* {@link java.util.Optional#empty()}.
*
* @return A function that consumes the argument and returns the
* empty option.
*/
static <T> Function<T, Optional<A>> functionise(Consumer<T> consumer) {
return a -> {
consumer.accept(a);
return Optional.empty();
};
}
Now that we have that method, we can create our new API. The simple case is one where we require
the user to pass the IOException handler. In this case, we have an API just like our previous version in
Listing 4-1, but we take two Consumer instances instead of two Function instances. The user is responsible
for deciding how to handle the IOException , should it occur, as well as how to handle the normal case.
The code for this is in Listing 4-5.
Listing 4-5. Method Accepting a Consumer to Process a Temporary File, and Calling a Callback on Error
/**
* Creates a temporary file, passes it into the given consumer, and
* deletes the temporary file when the function is complete.
*
* @param consumer The consumer to call with the temporary file, which is
* never {@code null}; may not be {@code null}
* @param exceptionHandler The handler for when an {@code IOException}
* occurs; may not be {@code null}
*/
public static void withTempFile(
Consumer<IOException> exceptionHandler,
Consumer<FunFile> consumer
 
Search WWH ::




Custom Search