導入
Java 21で導入された「Sequenced Collections」は、長年Java開発者を悩ませてきた「順序付きコレクションへのアクセス」という課題を根本から解決しました。これまで、LinkedHashSetなどの順序を保持するセットであっても、先頭や末尾の要素にアクセスするには、イテレータを回したり、一度リストに変換したりする必要がありました。SequencedSetを活用することで、これらの冗長なコードを排除し、可読性と保守性の高いコードを実現できます。
基礎知識
SequencedSetは、java.util.SequencedCollectionインターフェースを継承したSetの一種です。最大の特徴は、その要素が「遭遇順序(encounter order)」を持っていることです。
これまで、Setインターフェースには「順序」という概念が希薄でした。しかし、LinkedHashSetのように順序を保証する実装クラスに対しても、言語仕様として統一されたアクセス方法がありませんでした。SequencedSetは、先頭(First)と末尾(Last)に対して、要素の追加、取得、削除を行うメソッドを標準化しました。これにより、スタックやキューのような振る舞いをSetでも自然に扱えるようになりました。
実装/解決策
SequencedSetを利用するには、Java 21以上の環境でLinkedHashSetなどの実装クラスを使用します。主な操作メソッドには以下があります。
・addFirst(E e): 先頭に要素を追加
・addLast(E e): 末尾に要素を追加
・getFirst(): 先頭の要素を取得
・getLast(): 末尾の要素を取得
・removeFirst(): 先頭の要素を削除して返す
・removeLast(): 末尾の要素を削除して返す
・reversed(): 順序を逆にしたビューを返す
これらを使うことで、これまでCollections.reverse()を呼び出したり、手動で反復処理を書いていたロジックが、一行で記述可能になります。
サンプルプログラム
以下に、SequencedSetを活用した実用的なサンプルコードを示します。
import java.util.LinkedHashSet;
import java.util.SequencedSet;
public class SequencedSetExample {
public static void main(String[] args) {
// LinkedHashSetはJava 21からSequencedSetを実装しています
SequencedSet<String> orderedSet = new LinkedHashSet<>();
// 要素の追加
orderedSet.add("Java");
orderedSet.add("Python");
orderedSet.add("Go");
// 先頭への追加
orderedSet.addFirst("Rust");
// 末尾の取得
System.out.println("末尾の要素: " + orderedSet.getLast()); // 出力: Go
// 順序を反転させて処理(元のコレクションには影響しません)
System.out.println("逆順の要素:");
orderedSet.reversed().forEach(System.out::println);
// 先頭要素の安全な削除
String removed = orderedSet.removeFirst();
System.out.println("削除された先頭要素: " + removed);
}
}
応用・注意点
現場での開発において注意すべき点は、「すべてのSetが順序を持つわけではない」ということです。HashSetのような順序を保証しない実装クラスに対してSequencedSetのメソッドを呼び出すと、UnsupportedOperationExceptionが発生します。
また、reversed()メソッドが返すのは「コピー」ではなく「ビュー(View)」であるという点も重要です。ビューに対する変更は元のコレクションにも反映されますが、元のコレクションの構造が変更されると、ビュー側の動作が定義されない場合があります。
レガシーなコードをJava 21に移行する際は、まずはLinkedHashSetを使用している箇所を見つけ、Listへのキャストや面倒なイテレータ操作を行っているロジックを、SequencedSetのメソッドに置き換えることから始めてみてください。コードの意図が明確になり、バグの混入リスクを大幅に下げることができます。

コメント