Java 逆引き集 | サブリスト(subList)の注意点(ビュー) — 変更の影響範囲

Java Java
スポンサーリンク

サブリスト(subList)の注意点(ビュー) — 変更の影響範囲

Java の List.subList(from, to) は「部分リスト」を返しますが、これは コピーではなく元リストのビュー(見え方) です。初心者がよくつまずくのは「サブリストを変更すると元リストも変わる」「元リストを変更するとサブリストが壊れる」点です。安全に使うための知識を整理します。


基本の仕組み

  • ビュー: subList は元リストの一部を「見せる」だけ。新しいリストを作っているわけではない。
  • 範囲: from は開始インデックス(含む)、to は終了インデックス(含まない)。
  • 双方向の影響:
    • サブリストを変更すると元リストも変わる。
    • 元リストを変更するとサブリストも影響を受ける。
  • 構造変更の制約: 元リストに対してサブリストの範囲外で add/remove すると、サブリストは 不整合になり ConcurrentModificationException が出ることがある。

基本コード例

1. サブリストはビュー

import java.util.*;

public class SubListDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("A", "B", "C", "D", "E"));

        List<String> sub = list.subList(1, 4); // [B, C, D]
        System.out.println("sub = " + sub);

        sub.set(1, "X"); // sub[1] = "C" → "X"
        System.out.println("list = " + list); // [A, B, X, D, E] (元リストも変わる)
    }
}
Java

2. 元リストを変更するとサブリストが壊れる

List<String> list = new ArrayList<>(List.of("A", "B", "C", "D", "E"));
List<String> sub = list.subList(1, 4); // [B, C, D]

list.add("F"); // 元リストに範囲外の変更
System.out.println(sub); // ここで ConcurrentModificationException が出る可能性
Java

よくある用途と注意点

  • 部分削除: サブリストを clear() すると、その範囲が元リストから削除される。 list.subList(1, 3).clear(); // list の index 1〜2 を削除
  • 部分コピーが欲しい: new ArrayList<>(list.subList(...)) とすれば独立したコピーになる。ビューではなく新しいリスト。
  • 安全な利用: サブリストを使うときは「元リストに対して範囲外の構造変更をしない」ことが重要。

例題で練習

例題1: 部分削除

List<Integer> nums = new ArrayList<>(List.of(1,2,3,4,5,6));
nums.subList(2,5).clear(); // index 2〜4 を削除
System.out.println(nums); // [1, 2, 6]
Java

例題2: 部分コピーで安全に利用

List<String> list = new ArrayList<>(List.of("A","B","C","D","E"));
List<String> copy = new ArrayList<>(list.subList(1,4)); // 独立コピー
list.add("F"); // 元リスト変更しても copy は安全
System.out.println(copy); // [B, C, D]
Java

例題3: サブリストをソート

List<String> list = new ArrayList<>(List.of("E","D","C","B","A"));
List<String> sub = list.subList(1,4); // [D,C,B]
sub.sort(Comparator.naturalOrder());
System.out.println(list); // [E, B, C, D, A] (元リストも変わる)
Java

テンプレート集

  • 部分ビュー取得
List<T> sub = list.subList(fromIndex, toIndex);
Java
  • 部分削除
list.subList(from, to).clear();
Java
  • 部分コピー(安全)
List<T> copy = new ArrayList<>(list.subList(from, to));
Java
  • 部分ソート
list.subList(from, to).sort(comparator);
Java

実務でのコツ

  • ビューかコピーかを意識する: サブリストはビュー。独立したリストが欲しいならコピーを作る。
  • 元リストの構造変更に注意: サブリスト利用中は元リストに add/remove しない。
  • 範囲操作に便利: 部分削除や部分ソートはサブリストで簡潔に書ける。
  • 例外に備える: サブリストを保持したまま元リストを操作すると ConcurrentModificationException が出ることがあるので、設計で避ける。

まとめ

  • subListビューであり、元リストと内容を共有する。
  • サブリストの変更は元リストに反映され、逆も影響する。
  • 元リストの範囲外変更はサブリストを壊すので注意。
  • 独立した部分リストが欲しいなら new ArrayList<>(subList(...)) でコピーを作る。

👉 練習課題として「リストの中間部分を subList で取り出してソートし、元リストに反映させる」プログラムを書いてみると、ビューの性質がよく理解できます。

タイトルとURLをコピーしました