Spliterator(可分迭代器splitable iterator)
是java8中加入的另一个新接口。
java8中集合框架的所有集合都实现了spliterator
接口。
public interface Spliterator<T> {
boolean tryAdvance(Consumer<? super T> action);
Spliterator<T> trySplit();
long estimateSize();
int characteristics();
}
T是Spliterator
遍历的元素的类型。tryAdvance
方法的行为类似于普通的Iterator
,因为它会按顺序一个一个使用Spliterator
中的元素,并且如果还有其他元素要遍历就返回true。但trySplit
是专为Spliterator
接口设计的,因为它可以把一些元素划出去分给第二个Spliterator
(由该方法返回),让它们两个并行处理。Spliterator
还可通过estimateSize
方法估计还剩下多少元素要遍历,因为即使不那么确切,能快速算出来是一个值也有助于让拆分均匀一点。
7.3.1 拆分过程
将Stream拆分成多个部分的算法是一个递归过程,如图7-6所示。第一步是对第一个Spliterator调用trySplit,生成第二个Spliterator。第二步对这两个Spliterator调用trysplit,这样总共就有了四个
Spliterator。这个框架不断对Spliterator调用trySplit直到它返回null,表明它处理的数据结构不能再分割,如第三步所示。最后,这个递归拆分过程到第四步就终止了,这时所有的Spliterator在调用trySplit时都返回了null。
7.3.2 实现你自己的Spliterator
统计一个字符串中的字符
public static int countWords(String string) {
int count = 0;
char[] charArray = string.toCharArray();
boolean last = true;
for (char c : charArray) {
if (Character.isWhitespace(c)) { // 当前的是否为空格
last = true; // 如果当前的是空格,就不会走else了,所以对下一个而言,现在这个就是上一个
} else {
if (last) { // 上一个是空格且这一个不是空格
count++;
last = false;
}
}
}
return count;
}
String words = "The will of Kowloon is gathered here";
System.out.println(countWords(words));
输出 :
7
在进行归约操作时需要保存两个变量的值,一个是int
来记录之前有几个字符,另一个boolean
记录上一个字符是否为空格。
定义一个新类来存储状态
class WordStatus {
private final int count;
private final boolean isWord;
public WordStatus(int count, boolean isWord) {
this.count = count;
this.isWord = isWord;
}
public WordStatus accumulate(Character character) {
if (Character.isWhitespace(character)) { // 上一个是空格
return !isWord ? new WordStatus(count, true) : this;
} else {
return isWord ? new WordStatus(count + 1, false) : this;
}
}
public WordStatus combine(WordStatus other) {
return new WordStatus(count + other.count, other.isWord);
}
public int getCount() {
return count;
}
}
此时可以愉快地使用流来处理数单词的问题了
public static int countWords(Stream<Character> stream) {
return stream.reduce(new WordStatus(0, true), WordStatus::accumulate, WordStatus::combine).getCount();
}
Stream<Character> stream = IntStream.range(0, words.length()).mapToObj(words::charAt);
System.out.println(countWords(stream));
输出 :
7
但是当你想将其转换成并行流时会出错
stream = IntStream.range(0, words.length()).mapToObj(words::charAt);
System.out.println(countWords(stream.parallel()));
输出 :
30
因为它不知道该什么时候拆分,它可能会把一个单词拆成多个,导致单词被重数了。
下面是完整的代码
package lambdasinaction.chap7;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
class WordStatus {
private final int count;
private final boolean isWord;
public WordStatus(int count, boolean isWord) {
this.count = count;
this.isWord = isWord;
}
public WordStatus accumulate(Character character) {
if (Character.isWhitespace(character)) { // 上一个是空格
return !isWord ? new WordStatus(count, true) : this;
} else {
return isWord ? new WordStatus(count + 1, false) : this;
}
}
public WordStatus combine(WordStatus other) {
return new WordStatus(count + other.count, other.isWord);
}
public int getCount() {
return count;
}
}
class WordStatusSpliterator implements Spliterator<Character> {
private final String string;
private int currentChar = 0;
public WordStatusSpliterator(String string) {
this.string = string;
}
@Override
public boolean tryAdvance(Consumer<? super Character> action) {
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++) {
if (Character.isWhitespace(string.charAt(splitPos))) { // 找到空格了将字符串分成两部分
Spliterator<Character> wordStatusSpliterator = new WordStatusSpliterator(string.substring(currentChar, splitPos));
currentChar = splitPos; // 原来的字符串没动,但是通过调整currentChar相当于将前面的字符串切割出去了
return wordStatusSpliterator;
}
}
return null;
}
@Override
public long estimateSize() {
return string.length() - currentChar;
}
@Override
public int characteristics() {
return ORDERED | SIZED | IMMUTABLE | SUBSIZED | NONNULL;
}
}
public class Test03 {
public static int countWords(String string) {
int count = 0;
char[] charArray = string.toCharArray();
boolean last = true;
for (char c : charArray) {
if (Character.isWhitespace(c)) { // 当前的是否为空格
last = true; // 如果当前的是空格,就不会走else了,所以对下一个而言,现在这个就是上一个
} else {
if (last) { // 上一个是空格且这一个不是空格
count++;
last = false;
}
}
}
return count;
}
public static int countWords(Stream<Character> stream) {
return stream.reduce(new WordStatus(0, true), WordStatus::accumulate, WordStatus::combine).getCount();
}
public static void main(String[] args) {
String words = "The will of Kowloon is gathered here";
System.out.println(countWords(words));
System.out.println("===================================");
// 将字符串转换成字符流
Stream<Character> stream = IntStream.range(0, words.length()).mapToObj(words::charAt);
System.out.println(countWords(stream));
System.out.println("===================================");
stream = IntStream.range(0, words.length()).mapToObj(words::charAt);
System.out.println(countWords(stream.parallel()));
System.out.println("===================================");
Spliterator<Character> spliterator = new WordStatusSpliterator(words);
Stream<Character> streamed = StreamSupport.stream(spliterator, true);
System.out.println(countWords(streamed));
}
}
标签:count,return,int,WordStatus,Spliterator,7.3,public
From: https://blog.csdn.net/StarPlatinum2/article/details/144608191