AIによる要約
Listや配列の有効な添字は0から要素数-1までです。sizeやlengthと同じ値を指定すると範囲外になります。固定位置のget、空リストの先頭取得、ループ条件の<=、CSV列不足、ページング計算が主な原因です。例外をcatchして無視するのではなく、データ件数を確認し、固定位置へ依存しないAPIや事前検証を使い、境界値テストを追加します。


IndexOutOfBoundsExceptionは、指定した位置がコレクションや文字列の範囲外であるときに起きます。原因は単純に見えますが、CSVの列不足、検索0件、ページ番号、APIレスポンス変更など、入力データ側の変化で初めて表面化します。
例外行へifを1つ足すだけでは、なぜ件数が足りなかったのかを隠すことがあります。固定位置を使う設計が妥当か、0件を正常とするか、外部データ不正として止めるかを確認します。
この記事のポイント
- 有効な添字は0からsize-1まで
- ループ条件の<=は範囲外になりやすい
- 空Listへget(0)は使えない
- 固定列や固定位置を使う前に件数を検証する
- 例外をcatchして処理継続せずデータ契約を確認する
添字は0から始まる
3要素のListの添字は0、1、2です。size()は要素数3を返すため、そのままgetへ渡すと範囲外になります。
List<String> names = List.of("A", "B", "C");
System.out.println(names.get(0)); // A
System.out.println(names.get(2)); // C
System.out.println(names.get(3)); // IndexOutOfBoundsException『3件目』と『添字3』を混同しないよう、変数名をindex、position、rowNumberで分けます。画面の1始まりの行番号を添字へ変換する場合も境界で明示します。
ループ条件はi < size
添字で走査するfor文では、条件をi <= list.size()とすると最後にsizeと同じ値へ到達して例外になります。
for (int i = 0; i < names.size(); i++) {
System.out.println(names.get(i));
}要素だけが必要なら拡張forを使う方が添字ミスを避けられます。前後要素との比較、行番号の出力など、添字が必要な理由がある場合だけ通常forを使います。
空Listの先頭を無条件に取らない
検索結果の先頭をget(0)で取るコードは、0件時に失敗します。検索0件が正常か異常かを決め、戻り値の契約に合う方法を使います。
List<User> users = repository.findByEmail(email);
if (users.isEmpty()) {
throw new UserNotFoundException(email);
}
User user = users.get(0);1件だけを期待する検索なら、Repositoryの戻り値をOptionalにする、DBの一意制約を設定するなど、Listの先頭へ依存しない設計を検討します。2件以上も異常なら件数検証が必要です。
CSVの列不足で発生する
CSVを分割した配列から固定添字で値を取る処理は、末尾空項目や不正行で列数が足りないと失敗します。
String[] columns = line.split(",", -1);
if (columns.length != 5) {
throw new InvalidCsvException(
"期待列数=5, 実際=" + columns.length);
}
String userId = columns[0];
String email = columns[4];引用符を含むCSVはsplitだけで解析できません。ライブラリで列を解析した後でも、必須列数とヘッダーを検証し、何行目が不正か利用者へ返します。
ページング計算の境界
画面のページ番号が1始まり、内部のPageRequestが0始まりという違いもあります。1を引き忘れると1ページ目のつもりで2ページ目を取得し、最終ページで空になります。
int pageIndex = requestedPage - 1;
if (pageIndex < 0) {
throw new InvalidInputException("page", "1以上を指定してください");
}ページサイズ0、負数、総件数変動も確認します。フレームワークが例外を投げるまで任せず、外部入力として妥当な範囲をControllerで検証します。
subListとsubstringも終端に注意
subList(from, to)やsubstring(begin, end)は、開始位置を含み終了位置を含まない半開区間です。終了位置にはsizeやlengthを指定できますが、開始と終了の大小関係も必要です。
List<String> firstTwo = names.subList(0, 2); // A, B
String text = "ABCDE";
String part = text.substring(1, 3); // BC境界ルールが混在する自作APIを増やさず、Java標準の半開区間に合わせると読み手の予測が安定します。
catchして空値を返さない
範囲外例外をcatchし、空文字やnullを返すと、データ不正や実装バグが正常値に見えます。事前に件数を確認し、仕様に応じたエラーへ変換します。
// 避けたい例
try {
return columns[4];
} catch (IndexOutOfBoundsException e) {
return "";
}欠損列を空文字として補完する仕様なら、catchではなく列数検証と明示的な補完処理にします。意図がコードとログに残ります。
JUnitで0・1・最大・最大超過を確認する
境界値テストでは、0件、1件、最後の有効添字、sizeと同じ無効添字を用意します。ページングなら最初と最後のページも確認します。
@Test
void 最後の有効な要素を取得できる() {
List<String> values = List.of("A", "B", "C");
assertEquals("C", values.get(values.size() - 1));
}
@Test
void sizeと同じ添字は範囲外() {
List<String> values = List.of("A", "B", "C");
assertThrows(IndexOutOfBoundsException.class,
() -> values.get(values.size()));
}現場レビューでよくある指摘
範囲外例外のレビューでは、添字を1減らす修正だけでなく、件数不足が正常か異常か、固定位置依存が必要かを確認します。
// レビューコメント例
Listの有効な添字は0からsize-1です。
ループ条件をi < sizeへ変更してください。
// レビューコメント例
検索0件でget(0)が失敗します。0件を業務エラーにするか、
Optionalを返すRepositoryへ変更するか確認してください。
// レビューコメント例
CSV列数不足をIndexOutOfBoundsExceptionで検知しています。
固定位置へアクセスする前に期待列数を検証し、行番号付きエラーを返してください。正常データで再実行して終わらず、0件や列不足を作って修正を確認します。外部入力なら、利用者へ何を直せばよいか返せるエラーにします。
提出前のセルフチェック
レビュー前に確認すること
- 添字が0始まりであることを確認したか
- 最大有効値がsize-1か
- ループ条件がi < sizeか
- 空Listへget(0)していないか
- 固定列へアクセス前に列数を検証したか
- 画面の1始まりを内部0始まりへ変換したか
- 例外をcatchして空値で隠していないか
- 0・1・最大・最大超過をテストしたか
Javaの配列とコレクションを復習する参考書
添字、List、配列、ループの基本を一度まとめて確認すると、外部データやページングで起きる境界値の問題を切り分けやすくなります。
スッキリわかるJava入門 第5版
Java文法とオブジェクト指向を、最初から整理する一冊。
豊富な図とサンプルで、変数、条件分岐、クラス、例外処理まで順番に学べます。Javaの最初の教科書を探している人向けです。
- Javaを基礎から体系的に学びたい
- Java 25 LTS対応の入門書を選びたい
当サイトはAmazonアソシエイト・プログラムの参加者です。価格・在庫・配送条件はAmazonでご確認ください。
この記事とあわせて読みたい
まとめ
Listや配列の有効な添字は0から要素数-1までです。sizeと同じ添字、空Listのget(0)、ループ条件の<=、列不足がIndexOutOfBoundsExceptionの代表的な原因です。
例外をcatchして空値へ変えず、アクセス前に件数とデータ契約を検証します。0件、1件、最後の有効位置、範囲外をテストし、固定位置依存が本当に必要か確認してください。
