Java Reference
In-Depth Information
So we can now pull all this together. We will use Stream.of to create the single-element stream with a
ResultSet. That stream will have the ResultSet registered with it, so that the stream will close the ResultSet.
We will have a flatMap call that will be passed the iteration and stream building code: that code will be just
like we had in the previous section. This code is given in Listing 5-6.
Listing 5-6. Using Stream.of and Stream.flatMap to Convert a ResultSet to a Stream
public static Stream<WordUsage> createStream(ResultSet resultSet)
throws SQLException
{
Stream<ResultSet> rsStream = Stream.of(resultSet).onClose(() -> {
try {
resultSet.close();
} catch (SQLException ignore) {}
}
);
return rsStream.flatMap(rs -> {
Stream.Builder<WordUsage> builder = Stream.builder();
try {
while (rs.next()) {
WordUsage usage = WordUsage.fromResultSet(rs);
builder.add(usage);
}
} catch (SQLException sqle) {
// TODO Handle exceptions
}
return builder.build();
}
);
}
There are a number of advantages to this approach. The ResultSet is not processed until the stream
is actually exercised, which defers the expensive read from the ResultSet until and unless it is actually
needed. Exceptions that arise while reading the data are moved from the caller's flow into the flow of the
stream, which is a more appropriate place for them to be. The resulting stream will be the highly optimized
stream coming out of the Stream.Builder still, which is a major payoff. Finally, all the setup work for the
stream handling is allowed to take place before the execution of the result set and the processing, which will
streamline the execution.
The disadvantage of this approach is that it is still a hog, even if it is a deferred hog. All the results have
to be cached into memory before any of them can be processed. Also, the ResultSet must be fully read
before any result can be processed. This means that we cannot leverage the time waiting for the database
processing and network latency to process results that have already come in. We would like to start our
processing as quickly as possible, and that is where the next couple of alternatives come into play.
Mapping the ResultSet with Result-Based Error Handling
Another issue with this approach in Listing 5-6 is error handling: we are going to have a SQLException
instance being thrown, but what are we supposed to do with it? In Listing 5-6, we left a TODO and silently
swallowed it. We could wrap it in a RuntimeException and throw the unchecked exception, but then we
are ignoring an exception that we almost certainly want to be handling, and probably making a mess of our
types in the process. We can use the funjava.Result type from the FunJava library to solve this problem.
 
Search WWH ::




Custom Search