1. 導入:なぜTreeMapが必要なのか
Javaの開発において、Mapはキーと値のペアを扱う強力なツールですが、HashMapを使用した場合、要素の順序は保証されません。データの表示順を制御したい、あるいは「特定の範囲のキー」を抽出したいというケースは現場で頻繁に発生します。java.util.TreeMapは、キーを自然順序(または指定したComparator)でソートして保持するため、順序が重要なビジネスロジックにおいて非常に重要な役割を果たします。
2. 基礎知識:TreeMapの仕組み
TreeMapは、内部的に「赤黒木(Red-Black Tree)」という自己平衡二分探索木アルゴリズムを使用しています。
・特徴:挿入、削除、検索の計算量が常にO(log n)で保証されます。
・ソート:Map内のキーは、常にソートされた状態で維持されます。
・null値:キーにnullを指定すると、デフォルトの自然順序では例外(NullPointerException)が発生するため注意が必要です。
3. 実装/解決策
TreeMapを使いこなすためのポイントは、「比較ロジックの定義」です。基本型であれば自動でソートされますが、自作クラスをキーにする場合は、そのクラスがComparableインターフェースを実装しているか、TreeMapのコンストラクタでComparatorを渡す必要があります。これにより、昇順・降順を柔軟に切り替えることが可能です。
4. サンプルプログラム
以下は、IDをキーにして昇順で保持し、さらに特定の範囲のデータを抽出する実用的なサンプルです。
import java.util.TreeMap;
import java.util.Map;
public class TreeMapSample {
public static void main(String[] args) {
// キーをInteger、値をStringとしてTreeMapを作成
TreeMap userMap = new TreeMap<>();
// 順不同で追加しても自動でソートされる
userMap.put(3, "佐藤");
userMap.put(1, "田中");
userMap.put(4, "鈴木");
userMap.put(2, "高橋");
// 全要素を順に出力(1, 2, 3, 4の順になる)
System.out.println("--- 全ユーザー(昇順) ---");
userMap.forEach((id, name) -> System.out.println(id + ": " + name));
// 応用:IDが2以上4未満の範囲を取得する
System.out.println("--- 範囲指定抽出(2以上4未満) ---");
Map rangeMap = userMap.subMap(2, 4);
rangeMap.forEach((id, name) -> System.out.println(id + ": " + name));
}
}
5. 応用・注意点
現場でTreeMapを使用する際の注意点は以下の3点です。
・パフォーマンスの考慮:挿入のたびにソート処理が行われるため、HashMap(O(1))と比較すると書き込み負荷は高くなります。読み込みが多いケースや、順序が必要な場合に限定して使用してください。
・Sequenced Collectionsとの関係:Java 21以降、TreeMapはSequencedMapインターフェースを実装しました。これにより、firstEntry()やlastEntry()といったメソッドがより直感的に扱えるようになっています。
・比較の整合性:compareToメソッドの結果が0を返す場合、TreeMapでは「キーが重複している」とみなされ、値が上書きされます。キーをユニークにする設計を必ず守ってください。
TreeMapを正しく理解し、ソートロジックの自作という不毛な作業から解放されましょう!

コメント