java 8 stream 中 Spliterator 使用,開發利器!

作者:flydean 鏈接:https://juejin.im/post/5ea4ca3ae51d4546bb6f63c7

簡介

Spliterator是在java 8引入的一個接口,它通常和stream一起使用,用來遍歷和分割序列。

只要用到stream的地方都需要Spliterator,比如List,Collection,IO channel等等。

我們先看一下Collection中stream方法的定義:

<code>default Stream stream() {
return StreamSupport.stream(spliterator(), false);
}
/<code>
<code>default Stream parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
/<code>

我們可以看到,不管是並行stream還是非並行stream,都是通過StreamSupport來構造的,並且都需要傳入一個spliterator的參數。

好了,我們知道了spliterator是做什麼的之後,看一下它的具體結構:


java 8 stream 中 Spliterator 使用,開發利器!


spliterator有四個必須實現的方法,我們接下來進行詳細的講解。

tryAdvance

tryAdvance就是對stream中的元素進行處理的方法,如果元素存在,則對它進行處理,並返回true,否則返回false。

如果我們不想處理stream後續的元素,則在tryAdvance中返回false即可,利用這個特徵,我們可以中斷stream的處理。這個例子我將會在後面的文章中講到。

trySplit

trySplit嘗試對現有的stream進行分拆,一般用在parallelStream的情況,因為在併發stream下,我們需要用多線程去處理stream的不同元素,trySplit就是對stream中元素進行分拆處理的方法。

理想情況下trySplit應該將stream拆分成數目相同的兩部分才能最大提升性能。

estimateSize

estimateSize表示Spliterator中待處理的元素,在trySplit之前和之後一般是不同的,後面我們會在具體的例子中說明。

characteristics

characteristics表示這個Spliterator的特徵,Spliterator有8大特徵:

<code>public static final int ORDERED    = 0x00000010;//表示元素是有序的(每一次遍歷結果相同)
public static final int DISTINCT = 0x00000001;//表示元素不重複
public static final int SORTED = 0x00000004;//表示元素是按一定規律進行排列(有指定比較器)
public static final int SIZED = 0x00000040;//
表示大小是固定的
public static final int NONNULL = 0x00000100;//表示沒有null元素
public static final int IMMUTABLE = 0x00000400;//表示元素不可變
public static final int CONCURRENT = 0x00001000;//表示迭代器可以多線程操作
public static final int SUBSIZED = 0x00004000;//表示子Spliterators都具有SIZED特性/<code>

一個Spliterator可以有多個特徵,多個特徵進行or運算,最後得到最終的characteristics。

舉個例子

上面我們討論了Spliterator一些關鍵方法,現在我們舉一個具體的例子:

<code>@AllArgsConstructor
@Data
public class CustBook {
private String name;

}/<code>

先定義一個CustBook類,裡面放一個name變量。

定義一個方法,來生成一個CustBook的list:

<code>    public static List<custbook> generateElements() {
return Stream.generate(() -> new CustBook("cust book"))
.limit(1000)
.collect(Collectors.toList());
}/<custbook>/<code>

我們定義一個call方法,在call方法中調用了tryAdvance方法,傳入了我們自定義的處理方法。這裡我們修改book的name,並附加額外的信息。

<code>    public String call(Spliterator<custbook> spliterator) {
int current = 0;
while (spliterator.tryAdvance(a -> a.setName("test name"
.concat("- add new name")))) {
current++;
}

return Thread.currentThread().getName() + ":" + current;
}/<custbook>/<code>

最後,寫一下測試方法:

<code>    @Test
public void useTrySplit(){
Spliterator<custbook> split1 = SpliteratorUsage.generateElements().spliterator();
Spliterator<custbook> split2 = split1.trySplit();

log.info("before tryAdvance: {}",split1.estimateSize());
log.info("Characteristics {}",split1.characteristics());
log.info(call(split1));
log.info(call(split2));
log.info("after tryAdvance {}",split1.estimateSize());
}/<custbook>/<custbook>/<code>

運行的結果如下:

<code>23:10:08.852 [main] INFO com.flydean.SpliteratorUsage - before tryAdvance: 500
23:10:08.857 [main] INFO com.flydean.SpliteratorUsage - Characteristics 16464
23:10:08.858 [main] INFO com.flydean.SpliteratorUsage - main:500
23:10:08.858 [main] INFO com.flydean.SpliteratorUsage - main:500
23:10:08.858 [main] INFO com.flydean.SpliteratorUsage - after tryAdvance 0/<code>

List總共有1000條數據,調用一次trySplit之後,將List分成了兩部分,每部分500條數據。

注意,在tryAdvance調用之後,estimateSize變為0,表示所有的元素都已經被處理完畢。

再看一下這個Characteristics=16464,轉換為16進制:Ox4050 = ORDERED or SIZED or SUBSIZED 這三個的或運算。

這也是ArrayList的基本特徵。

總結

本文介紹了跟stream息息相關的接口Spliterator,討論了它的構成,並舉例說明,希望大家能夠掌握。


小福利

從正式成為一名程序員的那天起,註定要進行沒有止境的學習,堅持每天都高效的學習,私信回覆【666】送你

java 8 stream 中 Spliterator 使用,開發利器!


分享到:


相關文章: