1.Spliterator是Java 8中加入的另一个新接口;这个名字代表“可分迭代器”(splitable iterator)。和Iterator一样,Spliterator也用于遍历数据源中的元素,但它是为了并行执行 而设计的 .Java 8已经为集合框架中包含的所有数据结构提供了一个 默认的Spliterator实现,
集合实现了Spliterator接口,接口提供了一个spliterator方法。 这个接口定义了若干方法
public interface Spliterator<T> {
boolean tryAdvance(Consumer<? super T> action);
Spliterator<T> trySplit();
long estimateSize();
int characteristics(); }
tryAdvance方法的行为类似于普通的Iterator ,因为它会按照顺序一个个使用 Spliterator的元素,,并且如果还有其他元素要遍 历就返回true。但 trySplit是专为Spliterator接口设计的,因为它可以把一些元素划出去分 给第二个Spliterator(由该方法返回),让它们两个并行处理。Spliterator还可通过 estimateSize方法估计还剩下多少元素要遍历,因为即使不那么确切,能快速算出来是一个值 也有助于让拆分均匀一点
characteristics代表spliterator 本身特征的编码,使用 spliterator 的客户可以这些特性来更好地控制和 优化它的使用
实现自己的Spliterator
这是一个计算单词数量的方法
public class WordCounter { private final int counter; private final boolean lastSpace; public WordCounter(int counter, boolean lastSpace) { this.counter = counter; this.lastSpace = lastSpace; } public WordCounter accumulate(Character c){ if(Character.isWhitespace(c)){ return lastSpace? this: new WordCounter(counter,true); }else { return lastSpace? new WordCounter(counter +1,false):this ; } } public WordCounter combine(WordCounter WordCounter){ return new WordCounter(WordCounter.counter +counter, WordCounter.lastSpace); } public int getCounter() { return counter; } private int countWords(Stream<Character> stream) { WordCounter wordCounter = stream.reduce(new WordCounter(0,true),WordCounter::accumulate , WordCounter::combine); return wordCounter.getCounter(); } public static void main(String[] args) { final String SENTENCE = " Nel mezzo del cammin di nostra vita " + "mi ritrovai in una selva oscura" + " ché la dritta via era smarrita "; Stream<Character > stream = IntStream.range(0,SENTENCE.length()-1).mapToObj(SENTENCE ::charAt); }
}
输出结果: Found 19 words
这里的 accumulate方法定义了如何更改WordCounter的状,或更确切地说是用 哪个状态来建立新的WordCounter
2. 让WordCounter并行工作
你可以尝试用并行流来加快字数统计,如下所示:
System.out.println("Found " + countWords(stream.parallel()) + " words");
不幸的是,这次的输出是:
Found 25 words
因为原始的String在任意 位置拆分,所以有时一个词会被分为两个词,然后数了两次。如何解决这个问题呢?解决方案就是要确保String不是在随机位置拆开的,而只能在词尾 拆开。要做到这一点,你必须为Character实现一个Spliterator,它只能在两个词之间拆开 String然后由此创建并行流
class WordCounterSpliterator implements Spliterator<Character> { private final String string; private int currentChar = 0; public WordCounterSpliterator(String string) { this.string = string; } @Override public boolean tryAdvance(Consumer<? super Character> action) { System.out.println("currentChar " + currentChar); action.accept(string.charAt(currentChar++)); return currentChar < string.length(); } @Override public Spliterator<Character> trySplit() { int currentSize = string.length()-currentChar; if (currentSize<10) return null; for (int splitPos= currentSize/2+ currentChar;splitPos< string.length();splitPos++){ System.out.println("currentChar``` " + currentChar); if (Character.isWhitespace(string.charAt(splitPos))){ Spliterator<Character> spliterator = new WordCounterSpliterator(string.substring(currentChar, splitPos)); currentChar = splitPos; return spliterator; } } return null; } @Override public long estimateSize() { return string .length()-currentChar; } @Override public int characteristics() { return ORDERED + SIZED + SUBSIZED + NONNULL + IMMUTABLE; }
public static void main(String[] args) { final String SENTENCE = " Nel mezzo del cammin di nostra vita " + "mi ritrovai in una selva oscura" + " ché la dritta via era smarrita "; /*Stream<Character > stream = IntStream.range(0,SENTENCE.length()-1).mapToObj(SENTENCE ::charAt); System.out.println("Found " + countWords(stream) + " words"); */ Spliterator<Character> spliterator = new WordCounterSpliterator(SENTENCE); Stream<Character> stream = StreamSupport.stream(spliterator, true); System.out.println("Found " + countWords(stream) + " words"); }
}