【Modern Java】Java21で [ようやく|今更] 追加される Sequenced Collections (JEP 431)

blog1.mammb.com


はじめに

Java21 でコレクションフレームワークに順序付き要素のシーケンスを表すインターフェースが追加されます。

JEP 内容のポイントまとめです。


動機

コレクションフレームワークには、並び(encounter order)が規定された要素のシーケンスを表す型が不足している。

例えば、以下の様に。

  • ListDeque は要素の順序性が保証されるが、共通のスーパータイプは Collection であり、これには並びの定義は含まれない
  • SortedSetLinkedHashSet は並びの定義が成されるが、Set には並びの定義は含まれない
  • LinkedHashSetCollections::unmodifiableSet でラップすると、並びの定義の情報が失われる

並びを定義するシーケンス型がないため、最初の要素の取得/最後の要素の取得などの操作が各コレクションの独自実装となっており、一貫性が欠落している。


Sequenced の追加

以下の型を追加する。

  • SequencedCollection
  • SequencedSet
  • SequencedMap

これに伴い、コレクションフレームワークの型階層を以下のように変更する。


SequencedCollection

要素が 定義された順序を持つコレクション。 SequencedCollection には最初と最後の要素があり、それらの間の要素は、「前の要素」と「後ろの要素」を持つ。 どちらの端でも共通の操作をサポートし、要素を最初から最後、最後から最初に処理することをサポートする。

interface SequencedCollection<E> extends Collection<E> {
    // new method
    SequencedCollection<E> reversed();
    // methods promoted from Deque
    void addFirst(E);
    void addLast(E);
    E getFirst();
    E getLast();
    E removeFirst();
    E removeLast();
}

新しい reversed() メソッドは、元のコレクションを逆順に並べたビューを提供する(許可されている場合、ビューへの変更は元のコレクションに書き込まれる)。

例えば、LinkedHashSet から逆順のストリームを取得することは非常に困難であったが、以下のように簡略化される。

linkedHashSet.reversed().stream()


SequencedSet

シーケンスセットとは、重複する要素を含まない SequencedCollectionSet

interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {
    SequencedSet<E> reversed();    // covariant override
}

SortedSet のように相対比較で要素を配置するコレクションは、addFirst(E)addLast(E) のような明示的な配置操作をサポートできないため、UnsupportedOperationException をスローすることがある。


SequencedMap

エントリーが定義された順序を持つマップ。

interface SequencedMap<K,V> extends Map<K,V> {
    // new methods
    SequencedMap<K,V> reversed();
    SequencedSet<K> sequencedKeySet();
    SequencedCollection<V> sequencedValues();
    SequencedSet<Entry<K,V>> sequencedEntrySet();
    V putFirst(K, V);
    V putLast(K, V);
    // methods promoted from NavigableMap
    Entry<K, V> firstEntry();
    Entry<K, V> lastEntry();
    Entry<K, V> pollFirstEntry();
    Entry<K, V> pollLastEntry();
}

新しい put*(K, V) は、特殊なケースのセマンティクスを持つ。 LinkedHashMap のようなマップでは、エントリーがすでにマップに存在する場合、そのエントリーを再配置するという追加の効果があり、SortedMap などのマップでは、これらのメソッドは UnsupportedOperationException をスローする。


Collections.unmodifiableSequenced

Collectionsユーティリティクラスに、3つの新しいタイプ向けの unmodifiable ラッパーを追加する。

  • Collections.unmodifiableSequencedCollection(collection)
  • Collections.unmodifiableSequencedSet(sequencedSet)
  • Collections.unmodifiableSequencedMap(sequencedMap)