Java Reference
In-Depth Information
Example 8-43. The domain logic with file handling split out
public
public
List
<
String
>
findHeadings
(
Reader input
) {
return
return
withLinesOf
(
input
,
lines
->
lines
.
filter
(
line
->
line
.
endsWith
(
":"
))
.
map
(
line
->
line
.
substring
(
0
,
line
.
length
()-
1
))
.
collect
(
toList
()),
HeadingLookupException:
:
new
new
);
}
I expect that you're now wondering what that
withLinesOf
method looks like! It's shown in
Example 8-44. The definition of withLinesOf
private
private
<
T
>
T withLinesOf
(
Reader input
,
Function
<
Stream
<
String
>,
T
>
handler
,
Function
<
IOException
,
RuntimeException
>
error
) {
try
try
(
BufferedReader reader
=
new
new
BufferedReader
(
input
)) {
return
handler
.
apply
(
reader
.
lines
());
}
catch
return
catch
(
IOException e
) {
throw
throw
error
.
apply
(
e
);
}
}
withLinesOf
takes in a reader that handles the underlying file I/O. This is wrapped up in
BufferedReader
, which lets us read the file line by line. The
handler
function represents
the body of whatever code we want to use with this function. It takes the
Stream
of the file's
lines as its argument. We also take another handler called
error
that gets called when there's
an exception in the I/O code. This constructs whatever domain exception we want. This ex-
ception then gets thrown in the event of a problem.
To summarize, higher-order functions provide an inversion of control, which is a form of de-
pendency inversion. We can easily use them with lambda expressions. The other thing to
note with the dependency inversion principle is that the abstraction that we depend upon
doesn't have to be an
interface
. Here we've relied upon the existing
Stream
as an abstrac-
tion over raw reader and file handling. This approach also fits into the way that resource
management is performed in functional languages—usually a higher-order function manages
the resource and takes a callback function that is applied to an open resource, which is closed
afterward. In fact, if lambda expressions had been available at the time, it's arguable that the
try-with-resources
feature of Java 7 could have been implemented with a single library
function.