40-结果分析
结果分析
本案例的重点是 Spliterator 。该接口定义了可处理和分割要使用的元素源的方法,例如 Stream 对象的源。很少直接使用 Spliterator 对象。只有想要一个不同的行为时——也就是说,如果想实现自己的数据结构,并从它上创建流——使用 Spliterator 对象。
Spliterator 有一组可定义其行为的特征,如下所示。
CONCURRENT:可以同时安全地修改数据源。DISTINCT:数据源中的所有元素都是不同的。IMMUTABLE:可以在数据源中添加、删除或替换元素。NONNULL:数据源中没null值。ORDERED:在数据源的元素中遇到的一个问题。SIZED:由estimateSize()方法返回的值是Spliterator的确切大小。SORTED:对Spliterator的元素进行排序。SUBSIZED:调用trySplit()方法后,可以获得Spliterator的两个部分的确切大小。
在本案例中,我们定义了 Spliterator 的 DISTINCT 、 IMMUTABLE 、 NONNULL 、 ORDERED 、 SIZED 和 SUBSIZED 特性。
然后,我们实现了没有默认实现方案的 Spliterator 接口定义的所有方法。
characteristics():该方法返回Spliterator对象的特性。具体来说,它会返回一个整型值,可以使用Spliterator对象各个特性之间的按位或运算符(|)计算该值。要注意返回值与Spliterator对象的真实特征应该要一致。estimateSize():如果在当前调用它,则该方法返回由forEachRemaining()方法处理的元素数。在本案例中,它返回了已知的确切值,但方法的定义说明了这是估算的大小。tryAdvance():该方法将指定的参数作为参数应用于下一个要处理的元素(如果有)中,并返回true。如果没有要处理的元素,则它返回false。在本案例中,该方法收到一个Item对象处理的Consumer,但一次处理了一行Item对象。所以我们遍历了该行的所有项并调用了Consumer的accept()方法。trySplit():该方法可将当前的Spliterator分成两个不同的部分,因此每个部分可以由不同的线程处理。在理想的情况下,应该将数据源分成两部分,它们具有相同数量的元素。但是,在本案例中,我们计算了开始和结束索引之间的中间元素并生成了两个元素块。从开始到中间的部分由当前的Spliterator处理,而从中间到结束部分则由新的Spliterator对象处理。如果无法拆分数据源,则该方法返回null值。由于在本案例中,Spliterator只有两个元素,所以不会分割它。
Spliterator 接口的其他方法有一个默认实现。我们重写了 forEachRemaining() 方法,该方法将收到的函数接口对象作为参数( Consumer 接口的实现)应用于尚未处理的 Spliterator 元素。我们实现自己的版本以在控制台中打印消息。我们用 tryAdvance() 方法来处理每个单独项。
下图显示了本例的部分输出结果。
首先,调用 trySplit() 方法来分割数据源,然后调用 forEachRemaining() 方法来处理由 trySplit() 方法生成的每个 Spliterator 中的所有元素。