1. 導入
実務でMapを扱う際、単に「キーと値のペアを保持する」だけでなく、「キー順に並べ替えて処理したい」「特定の条件に近いキーを探したい」という場面は頻繁に発生します。例えば、時系列データの処理や、範囲検索が必要なキャッシュの実装などです。Javaの標準APIであるSortedMapやNavigableMapを活用することで、自前でソート処理やループ処理を書く手間を省き、コードの可読性と保守性を大幅に向上させることができます。
2. 基礎知識
まず前提として、Mapインターフェースは順序を保証しません。これに対し、SortedMapは「キーが自然順序(または指定したComparator)」に従ってソートされていることを保証するインターフェースです。
さらに、Java 6で導入されたNavigableMapはSortedMapを継承しており、ソート機能に加えて「指定した値に近いキーを検索する(近傍探索)」機能が強化されています。例えば、「指定した日付より前の最新データ」や「ある数値を下回る最大の要素」といった検索が、非常に効率的に行えます。
3. 実装/解決策
NavigableMapの代表的な実装クラスであるTreeMapを使用します。
NavigableMapの強力な点は、lowerKey(未満)、floorKey(以下)、ceilingKey(以上)、higherKey(超える)といったメソッド群です。これらを活用すれば、複雑なif文やループを記述することなく、目的のデータに直接アクセスできます。特に検索アルゴリズムを自前で実装する必要がないため、バグの混入リスクを下げることができます。
4. サンプルプログラム
以下は、売上データを保持し、特定の金額に近い検索を行う実用的なコード例です。
import java.util.NavigableMap;
import java.util.TreeMap;
public class MapExample {
public static void main(String[] args) {
// TreeMapを使用してNavigableMapを生成(キー:金額、値:商品名)
NavigableMap
salesMap.put(1000, “商品A”);
salesMap.put(3000, “商品B”);
salesMap.put(5000, “商品C”);
// 3000円未満の最大のキーを取得
Integer lower = salesMap.lowerKey(3000);
System.out.println(“3000円未満の最大のキー: ” + lower); // 結果: 1000
// 4000円以上の最小のキーを取得
Integer ceiling = salesMap.ceilingKey(4000);
System.out.println(“4000円以上の最小のキー: ” + ceiling); // 結果: 5000
// 範囲指定でサブマップを取得(メモリ効率が良いビューとして機能)
NavigableMap
System.out.println(“1000から4000の範囲: ” + range);
}
}
5. 応用・注意点
実務で利用する際の重要な注意点がいくつかあります。
1. 計算量への意識: TreeMapの操作(put, get, removeなど)は、内部的に赤黒木(Red-Black Tree)というデータ構造を使用しているため、計算量は常にO(log n)です。データ件数が膨大になる場合は、HashMap(O(1))とのパフォーマンス比較を考慮してください。
2. nullの扱い: TreeMapはキーにnullを許可しません。nullをputしようとするとNullPointerExceptionが発生します。データソースにnullが含まれる可能性がある場合は、事前にフィルタリングが必要です。
3. Sequenced Collectionsとの関係: Java 21から導入されたSequencedMapインターフェースにより、SortedMapやNavigableMapも「先頭・末尾へのアクセス」が標準化されました。最新のJava環境であれば、getFirst()やpollLastEntry()などを積極的に利用することで、より直感的なコードが書けます。
これらのインターフェースを適切に使いこなすことで、データ構造を活かした、堅牢で効率的なビジネスロジックを構築してください。

コメント