Java Reference
In-Depth Information
There are a number of characteristics, and they are treated as a bitfield. The two most important are
IMMUTABLE and CONCURRENT , and those specify the relationship of the spliterator to the source. If the spliterator's
view of the source cannot be changed, then the spliterator should specify IMMUTABLE . This will be the case with
our ResultSet spliterator, since the results of a SQL query cannot be changed. Alternatively, if the spliterator's
view of the source can be concurrently modified, then the spliterator should specify CONCURRENT. This could
be the case in a spliterator that acted on a thread-safe collection or a memory-mapped file.
There are a few other characteristics that a spliterator can have. Unlike IMMUTABLE and
CONCURRENT, which are mutually exclusive, these are more distinct: none of the following characteristics
excludes the others. The most significant is ORDERED. This characteristic guarantees that elements will
be processed in “encounter order,” which is the iteration order for the spliterator. If you pass ORDERED to
a spliterator, you will have an API that is akin to a sequential stream — there's still some wiggle room for
parallelism in the implementation, but not much. If you are ORDERED, you can also be SORTED. If your
spliterator is SORTED, then either your spliterator has a comparator attached, or the elements are sorted
according to their natural ordering. This allows some optimizations for sorting, and also allows the results
of the spliterator to be processed in parallel and then sorted back into order. The DISTINCT flag signals that
each element of the spliterator is distinct from every other element. This signals that no additional work is
needed to filter out redundant values, such as in Stream.distinct() . The NONNULL characteristic asserts
that no result from the spliterator will ever be null, which allows some safety checks to be bypassed. Finally,
the SIZED and SUBSIZED characteristics both assert that the estimated size for the spliterator is accurate.
SUBSIZED additionally guarantees that spliterators that are split off this spliterator will themselves be SIZED
and SUBSIZED: in other words, SUBSIZED means that not only is the total number of elements known, but if
there is a breakout of elements into distinct spliterators, then the partial sizes are also known.
In our case, every row will create an instance, so we can use the NONNULL characteristic. Since it is
best to avoid null in general, we can make this directly in our class. In our particular case, we also know that
every resulting WordUsage instance is distinct from the others, so we can use the DISTINCT characteristic.
However, this is not necessarily the case for every SQL query. We do not know the total number of instances
we will create, so we cannot be SIZED. We also don't have any ordering in our current query and don't really
have any need for an ordering, so we won't be ORDERED. Finally, the results of the SQL query cannot be
modified during our iteration, so we can return the IMMUTABLE option. With that decided, we can build
out the constructor, giving us the class in Listing 5-10.
Listing 5-10. The ResultSetSpliterator with Constructor
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.function.*;
/**
* A {@link java.util.Spliterator} that traverses a
* {@link java.sql.ResultSet}. When the result set is exhausted,
* it will be automatically closed. Implementing classes must implement
* {@link #processRow(java.sql.ResultSet)} to
* specify how to convert a row into a result object.
*/
public abstract class ResultSetSpliterator<RESULT_T>
extends Spliterators.AbstractSpliterator<RESULT_T>
{
 
Search WWH ::




Custom Search