Java : Spliterator - API使用例

Spliterator (Java SE 16 & JDK 16)の使用例まとめです。
だいたいのメソッドを網羅済みです。
公式API仕様のおともにどうぞ。


概要

クラス構成

Spliteratorインタフェースは、コレクションや配列などの要素に順次アクセスするためのAPIです。
既存のAPIではIteratorに近いですね。

final var list = List.of("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]
System.out.println(list.size()); // 3

final var spliterator = list.spliterator();

spliterator.forEachRemaining(s -> {
    //aaa
    //bbb
    //ccc
    System.out.println(s);
});

また、Split(分割)という名前のとおり、1つのSpliteratorを2つに分割することができます。

final var list = List.of("a", "b", "c", "d", "e");
System.out.println(list); // [a, b, c, d, e]
System.out.println(list.size()); // 5

final var s1 = list.spliterator();
System.out.println("s1 size : " + s1.estimateSize()); // s1 size : 5

final var s2 = s1.trySplit();
System.out.println("s1 size : " + s1.estimateSize()); // s1 size : 3
System.out.println("s2 size : " + s2.estimateSize()); // s2 size : 2

//c
//d
//e
s1.forEachRemaining(System.out::println);

//a
//b
s2.forEachRemaining(System.out::println);

分割の用途としては、

  • それぞれのSpliteratorを並列で処理することによりパフォーマンス向上を期待

という感じでしょうか。

フィールド

static int CONCURRENT

外部同期を使用せずに、複数のスレッドで並行して要素のソースを安全に変更できる(追加、置換、削除が可能)ことを示す特性値です。

final var queue = new ConcurrentLinkedQueue<String>();
queue.add("a");
queue.add("b");

final var spliterator = queue.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x1110

System.out.printf("CONCURRENT : 0x%x\n", Spliterator.CONCURRENT); // CONCURRENT : 0x1000
System.out.printf("NONNULL : 0x%x\n", Spliterator.NONNULL); // NONNULL : 0x100
System.out.printf("ORDERED : 0x%x\n", Spliterator.ORDERED); // ORDERED : 0x10

static int DISTINCT

検出された要素の各ペアx, yに対して!x.equals(y)であることを示す特性値です。

final var set = new HashSet<String>();
set.add("a");
set.add("b");

final var spliterator = set.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x41

System.out.printf("SIZED : 0x%x\n", Spliterator.SIZED); // SIZED : 0x40
System.out.printf("DISTINCT : 0x%x\n", Spliterator.DISTINCT); // DISTINCT : 0x1

static int IMMUTABLE

要素のソースが構造的に変更不可であることを示す特性値です。つまり、要素の追加、置換および削除ができないため、トラバース中に変更が発生する可能性はありません。

final var list = new CopyOnWriteArrayList<String>();
list.add("a");
list.add("b");

final var spliterator = list.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x4450

System.out.printf("SUBSIZED : 0x%x\n", Spliterator.SUBSIZED); // SUBSIZED : 0x4000
System.out.printf("IMMUTABLE : 0x%x\n", Spliterator.IMMUTABLE); // IMMUTABLE : 0x400
System.out.printf("SIZED : 0x%x\n", Spliterator.SIZED); // SIZED : 0x40
System.out.printf("ORDERED : 0x%x\n", Spliterator.ORDERED); // ORDERED : 0x10

static int NONNULL

ソースで検出される要素がnullではないことが保証されることを示す特性値です。

final var deque = new ArrayDeque<String>();
deque.add("a");
deque.add("b");
//deque.add(null); // NullPointerException発生

final var spliterator = deque.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x4150

System.out.printf("SUBSIZED : 0x%x\n", Spliterator.SUBSIZED); // SUBSIZED : 0x4000
System.out.printf("NONNULL : 0x%x\n", Spliterator.NONNULL); // NONNULL : 0x100
System.out.printf("SIZED : 0x%x\n", Spliterator.SIZED); // SIZED : 0x40
System.out.printf("ORDERED : 0x%x\n", Spliterator.ORDERED); // ORDERED : 0x10

static int ORDERED

要素の検出順序が定義されていることを示す特性値です。

final var list = new ArrayList<String>();
list.add("a");
list.add("b");

final var spliterator = list.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x4050

System.out.printf("SUBSIZED : 0x%x\n", Spliterator.SUBSIZED); // SUBSIZED : 0x4000
System.out.printf("SIZED : 0x%x\n", Spliterator.SIZED); // SIZED : 0x40
System.out.printf("ORDERED : 0x%x\n", Spliterator.ORDERED); // ORDERED : 0x10

static int SIZED

構造的なソース変更がない場合に、トラバースまたは分割の前にestimateSize()から返される値が完全なトラバースで検出される要素数の正確なカウントを表す有限サイズを表すことを示す特性値です。

final var list = new ArrayList<String>();
list.add("a");
list.add("b");

final var spliterator = list.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x4050

System.out.printf("SUBSIZED : 0x%x\n", Spliterator.SUBSIZED); // SUBSIZED : 0x4000
System.out.printf("SIZED : 0x%x\n", Spliterator.SIZED); // SIZED : 0x40
System.out.printf("ORDERED : 0x%x\n", Spliterator.ORDERED); // ORDERED : 0x10

static int SORTED

検出順序が定義済みのソート順序に従うことを示す特性値です。

final var set = new TreeSet<String>();
set.add("a");
set.add("b");

final var spliterator = set.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x55

System.out.printf("SIZED : 0x%x\n", Spliterator.SIZED); // SIZED : 0x40
System.out.printf("ORDERED : 0x%x\n", Spliterator.ORDERED); // ORDERED : 0x10
System.out.printf("SORTED : 0x%x\n", Spliterator.SORTED); // SORTED : 0x4
System.out.printf("DISTINCT : 0x%x\n", Spliterator.DISTINCT); // DISTINCT : 0x1

static int SUBSIZED

trySplit()で生成されたすべてのスプリッテレータがSIZEDとSUBSIZEDの両方であることを示す特性値です。

final var list = new ArrayList<String>();
list.add("a");
list.add("b");

final var spliterator = list.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x4050

System.out.printf("SUBSIZED : 0x%x\n", Spliterator.SUBSIZED); // SUBSIZED : 0x4000
System.out.printf("SIZED : 0x%x\n", Spliterator.SIZED); // SIZED : 0x40
System.out.printf("ORDERED : 0x%x\n", Spliterator.ORDERED); // ORDERED : 0x10

メソッド

int characteristics ()

このスプリッテレータおよびその要素の、一連の特性を返します。

API使用例は、フィールドのORDEREDSIZEDなどにまとめて記載しました。
そちらをご参照ください。

long estimateSize ()

forEachRemaining(java.util.function.Consumer<? super T>)のトラバースで検出される要素数の推定値を返します。無限大または不明の場合、あるいはコストが高すぎて計算できない場合は、Long.MAX_VALUEを返します。

final var list = List.of("a", "b", "c", "d", "e");
System.out.println(list); // [a, b, c, d, e]
System.out.println(list.size()); // 5

final var spliterator = list.spliterator();
System.out.println(spliterator.estimateSize()); // 5
System.out.println(spliterator.getExactSizeIfKnown()); // 5
final var queue = new ConcurrentLinkedQueue<String>();
queue.add("a");
queue.add("b");
queue.add("c");

System.out.println(queue); // [a, b, c]
System.out.println(queue.size()); // 3

final var spliterator = queue.spliterator();
System.out.println(spliterator.estimateSize()); // 9223372036854775807 ( long の最大値 )
System.out.println(spliterator.getExactSizeIfKnown()); // -1

default void forEachRemaining (Consumer<? super T> action)

すべての要素の処理が完了するかアクションから例外がスローされるまで、現在のスレッド内で残りの各要素に対して指定されたアクションをシーケンシャルに実行します。

final var list = List.of("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]
System.out.println(list.size()); // 3

final var spliterator = list.spliterator();

spliterator.forEachRemaining(s -> {
    //aaa
    //bbb
    //ccc
    System.out.println(s);
});

default Comparator<? super T> getComparator ()

このスプリッテレータのソースがComparatorによってソートされている(SORTED)場合は、そのComparatorを返します。

final var set = new TreeSet<String>();
set.add("c");
set.add("d");
set.add("a");
set.add("b");

System.out.println(set); // [a, b, c, d]

final var spliterator = set.spliterator();
final var comparator = spliterator.getComparator();

// nullの場合は自然順序によってソートされています。
System.out.println(comparator); // null
// 自然順序の逆順でソートします。
final Comparator<String> reverse = Comparator.reverseOrder();

final var set = new TreeSet<>(reverse);
set.add("c");
set.add("d");
set.add("a");
set.add("b");

System.out.println(set); // [d, c, b, a]

final var spliterator = set.spliterator();
final var comparator = spliterator.getComparator();
System.out.println(comparator); // java.util.Collections$ReverseComparator@2c83f1d1
final var list = List.of("a", "b", "c");
System.out.println(list); // [a, b, c]

final var spliterator = list.spliterator();
//final var comparator = spliterator.getComparator(); // IllegalStateException発生

default long getExactSizeIfKnown ()

このスプリッテレータがSIZEDである場合はestimateSize()を返し、そうでない場合は-1を返す簡易メソッドです。

API使用例は estimateSize() にまとめて記載しました。
そちらのメソッドをご参照ください。

default boolean hasCharacteristics (int characteristics)

指定されたすべての特性がこのスプリッテレータのcharacteristics()に含まれている場合はtrueを返します。

final var set = new HashSet<String>();
set.add("a");
set.add("b");

final var spliterator = set.spliterator();

System.out.printf("0x%x\n", spliterator.characteristics()); // 0x41

System.out.printf("SIZED : 0x%x\n", Spliterator.SIZED); // SIZED : 0x40
System.out.printf("DISTINCT : 0x%x\n", Spliterator.DISTINCT); // DISTINCT : 0x1

System.out.println(spliterator.hasCharacteristics(Spliterator.SIZED)); // true
System.out.println(spliterator.hasCharacteristics(Spliterator.DISTINCT)); // true
System.out.println(spliterator.hasCharacteristics(Spliterator.ORDERED)); // false

boolean tryAdvance (Consumer<? super T> action)

残りの要素が存在する場合は、指定されたアクションをそれに対して実行し、trueを返します。それ以外の場合はfalseを返します。

final var list = List.of("aaa", "bbb", "ccc");
final var spliterator = list.spliterator();

System.out.println(spliterator.tryAdvance(System.out::println));
System.out.println(spliterator.tryAdvance(System.out::println));
System.out.println(spliterator.tryAdvance(System.out::println));
System.out.println(spliterator.tryAdvance(System.out::println));

// 結果
// ↓
//aaa
//true
//bbb
//true
//ccc
//true
//false

Spliterator<T> trySplit ()

このspliteratorをパーティション化できる場合に、要素に適用されるSpliteratorを返します。このメソッドから戻ると同時に、それらの要素にはこのSpliteratorが適用されなくなります。

final var list = List.of("a", "b", "c", "d", "e");
System.out.println(list); // [a, b, c, d, e]
System.out.println(list.size()); // 5

final var s1 = list.spliterator();
System.out.println("s1 size : " + s1.estimateSize()); // s1 size : 5

final var s2 = s1.trySplit();
System.out.println("s1 size : " + s1.estimateSize()); // s1 size : 3
System.out.println("s2 size : " + s2.estimateSize()); // s2 size : 2

//c
//d
//e
s1.forEachRemaining(System.out::println);

//a
//b
s2.forEachRemaining(System.out::println);

関連記事

ページの先頭へ