Java Reference
In-Depth Information
The when methods provide support for a fluent API, which allows you to write functional code that looks
like imperative code to the reader. They return the current object for chaining, so you can call the methods in
order, providing something that looks a lot like a try/catch block with exceptions at the end.
The very last when method is for catching multiple types of exceptions, and it is a great demonstration
of the power of Java 8. Thanks to type inference, the consumer's argument will be automatically set to the
broadest common superclass of the methods to be caught. The traditional implementation would involve
null , if blocks, and loops, but those are all replaced by the Optional and Stream class methods.
Using this Result class, we can encapsulate the result of a method call. Instead of returning a RETURN_T ,
we return a Result<RETURN_T> . When the method executes, it will construct a Result instance with either
the return value of the user's function, or with the IOException that was thrown. An initial pass at the code
might look something like this:
<RETURN_T> Result<RETURN_T> withTempFile(Function<File, RETURN_T> function) {
Objects.requireNonNull(function, "function to apply to temp file");
Optional<File> file = Optional.empty();
try {
file = Optional.of(File.createTempFile("funfile", "tmp"));
return new Result<>(file.map(function).get());
} catch (IOException e) {
return new Result<>(e);
} finally {
file.ifPresent(File::delete);
}
} // This code would work, but could do with improvement: read on!
This code bears a striking resemblance to the code in Listing 4-1. If you let your eyes blur a little bit and
just look at the profile of the function in the whitespace, you will see that the method has the same shape.
Any time that you have two methods with the same shape, you are missing an opportunity for code reuse. In
this case, the code is almost identical except on the return lines: in Listing 4-1, the return lines delegate to
user-given code. In our new method, we want to call the Return class constructors at that point. We can pass
the Return class constructors into the Listing 4-1 code as the user-given code, thereby delegating the actual
implementation of the temp file into a single place. The resulting delegation code is given in Listing 4-3, and
it is extremely simple. This demonstrates again how powerful the new paradigm is in our postfunctional Java
world.
Listing 4-3. Temp File Creation with Exceptions Encapsulated in the Return Value
/**
* Creates a temporary file, passes it into the given function, and
* deletes the temporary file when the function is complete.
*
* @param function The behavior to implement with the temporary file,
* which may not return {@code null}; may not be {@code null}
* @return The result of the given function
*/
public static <RETURN_T> Result<RETURN_T> withTempFile(
Function<File, RETURN_T> function
) {
Objects.requireNonNull(function, "function to apply to temp file");
Function<File, Result<RETURN_T>> resultify = function.andThen(Result::new);
return withTempFile(Result::new, resultify);
}
 
Search WWH ::




Custom Search