広告

Java : Spliterator - API使用例

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


概要

ソースの要素をトラバースおよびパーティション化するためのオブジェクトです。 スプリッテレータが適用される要素のソースは、配列、Collection、IOチャネル、ジェネレータ関数などです。

クラス構成

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();

System.out.println("-- forEachRemaining --");
spliterator.forEachRemaining(s -> {
    System.out.println(s);
});

// 結果
// ↓
//-- forEachRemaining --
//aaa
//bbb
//ccc

また、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

System.out.println("-- s1 --");
s1.forEachRemaining(System.out::println);

// 結果
// ↓
//-- s1 --
//c
//d
//e

System.out.println("-- s2 --");
s2.forEachRemaining(System.out::println);

// 結果
// ↓
//-- s2 --
//a
//b

フィールド

static final 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 final 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 final 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 final 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 final 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 final 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 final 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 final 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 ()

このSpliteratorおよびその要素の特性のセットを返します。

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() == Long.MAX_VALUE); // true
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();

System.out.println("-- forEachRemaining --");
spliterator.forEachRemaining(s -> {
    System.out.println(s);
});

// 結果
// ↓
//-- forEachRemaining --
//aaa
//bbb
//ccc

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 == reverse); // true
final var list = List.of("a", "b", "c");
System.out.println(list); // [a, b, c]

final var spliterator = list.spliterator();

try {
    final var comparator = spliterator.getComparator();
} catch (IllegalStateException e) {
    System.out.println("IllegalStateException!");
}

// 結果
// ↓
//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("-- tryAdvance --");
final var ret1 = spliterator.tryAdvance(System.out::println);
System.out.println("ret : " + ret1);

System.out.println("-- tryAdvance --");
final var ret2 = spliterator.tryAdvance(System.out::println);
System.out.println("ret : " + ret2);

System.out.println("-- tryAdvance --");
final var ret3 = spliterator.tryAdvance(System.out::println);
System.out.println("ret : " + ret3);

System.out.println("-- tryAdvance --");
final var ret4 = spliterator.tryAdvance(System.out::println);
System.out.println("ret : " + ret4);

// 結果
// ↓
//-- tryAdvance --
//aaa
//ret : true
//-- tryAdvance --
//bbb
//ret : true
//-- tryAdvance --
//ccc
//ret : true
//-- tryAdvance --
//ret : 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

System.out.println("-- s1 --");
s1.forEachRemaining(System.out::println);

// 結果
// ↓
//-- s1 --
//c
//d
//e

System.out.println("-- s2 --");
s2.forEachRemaining(System.out::println);

// 結果
// ↓
//-- s2 --
//a
//b

関連記事

ページの先頭へ