13.

Java のよくある例外・エラー一覧と対処法 — NPE / ClassNotFoundException / OOM ほか

編集
この記事の要点
  • Java の例外は RuntimeException (非検査)Exception (検査) に分かれる
  • 最頻出は NullPointerException。null チェック・Optional・Objects.requireNonNull で予防
  • ClassNotFoundExceptionNoClassDefFoundError は別物。前者はロード時、後者は初期化中に発生
  • コレクション操作中の変更で ConcurrentModificationException が出る → Iterator.remove や CopyOnWriteArrayList を使う
  • OutOfMemoryError はメモリ不足。ヒープダンプ -XX:+HeapDumpOnOutOfMemoryError で解析

Java の例外階層

Throwable
├── Error                          (回復不能、捕捉非推奨)
│   ├── OutOfMemoryError
│   ├── StackOverflowError
│   └── NoClassDefFoundError
└── Exception
    ├── RuntimeException           (非検査例外: catch 不要)
    │   ├── NullPointerException
    │   ├── ArrayIndexOutOfBoundsException
    │   ├── ClassCastException
    │   ├── NumberFormatException
    │   ├── ConcurrentModificationException
    │   ├── UnsupportedOperationException
    │   └── IllegalArgumentException
    └── (検査例外: catch または throws 必須)
        ├── IOException
        ├── SQLException
        └── ClassNotFoundException

1. NullPointerException (NPE)

最頻出。null の参照型に対してメソッド・フィールドアクセスした場合に発生。

String name = null;
int len = name.length();    // ❌ NullPointerException

// 対処1: null チェック
if (name != null) {
    int len = name.length();
}

// 対処2: Optional
Optional.ofNullable(name).map(String::length).ifPresent(System.out::println);

// 対処3: 定数を左に置く (文字列比較)
if ("admin".equals(role)) { ... }  // role が null でも安全

// 対処4: Objects.requireNonNull で早期失敗
public void setName(String name) {
    this.name = Objects.requireNonNull(name, "name must not be null");
}

// Java 14+ Helpful NullPointerExceptions
// → "Cannot invoke 'String.length()' because 'name' is null" のように原因を表示

2. ClassNotFoundException / NoClassDefFoundError

ClassNotFoundExceptionNoClassDefFoundError
種類検査例外Error
発生タイミングClass.forName() / リフレクションでクラスをロード時クラスのリンク・初期化時
典型原因クラスパスに JAR が無い初期化中の static 初期化で例外発生
対処クラスパスに JAR を追加static 初期化の例外を直す / 依存 JAR を確認
Exception in thread "main" java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
→ MySQL ドライバ JAR をクラスパスに追加

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
    Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
→ SLF4J の依存が pom.xml に無い、または scope=provided になっている

3. ArrayIndexOutOfBoundsException

int[] arr = {1, 2, 3};
int x = arr[5];   // ❌ ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3

// 対処: 範囲チェック
if (i >= 0 && i < arr.length) {
    int x = arr[i];
}

// 拡張 for で防ぐ
for (int v : arr) {
    System.out.println(v);
}

// 同種: StringIndexOutOfBoundsException
"abc".charAt(10);  // ❌

4. ClassCastException

Object obj = "hello";
Integer i = (Integer) obj;   // ❌ ClassCastException

// 対処1: instanceof で事前確認
if (obj instanceof Integer i2) {   // Java 16+ パターンマッチ
    System.out.println(i2 + 1);
}

// 対処2: ジェネリクスを使い raw type を避ける
List list = new ArrayList<>();
list.add("a");
String s = list.get(0);   // キャスト不要で安全

5. ConcurrentModificationException

List list = new ArrayList<>(List.of("a", "b", "c"));

// ❌ 拡張 for の中で remove → ConcurrentModificationException
for (String s : list) {
    if (s.equals("b")) list.remove(s);
}

// ✅ 対処1: Iterator.remove
Iterator it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("b")) it.remove();
}

// ✅ 対処2: removeIf (Java 8+)
list.removeIf(s -> s.equals("b"));

// ✅ 対処3: 並行アクセスなら CopyOnWriteArrayList
List safe = new CopyOnWriteArrayList<>(list);

6. StackOverflowError

// 無限再帰でスタックが溢れる
public int factorial(int n) {
    return n * factorial(n - 1);   // ❌ 終了条件無し
}

// 対処: 終了条件を入れる
public int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

// JVM 引数でスタックサイズ調整 (緊急避難)
// java -Xss2m MyApp

7. OutOfMemoryError

java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Metaspace
java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: Direct buffer memory

対処:

  • ヒープサイズを増やす: java -Xmx2g -Xms512m MyApp
  • ヒープダンプを取得: -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp
  • VisualVM / Eclipse MAT でメモリリーク調査
  • Metaspace の場合: -XX:MaxMetaspaceSize=256m

8. UnsupportedOperationException

// 不変リストへの変更
List nums = List.of(1, 2, 3);   // 不変
nums.add(4);   // ❌ UnsupportedOperationException

// Arrays.asList も追加・削除不可
List a = Arrays.asList(1, 2, 3);
a.add(4);   // ❌

// 対処: 可変リストにコピー
List mutable = new ArrayList<>(nums);
mutable.add(4);   // ✅

9. NumberFormatException

int n = Integer.parseInt("abc");   // ❌ NumberFormatException
int m = Integer.parseInt("");      // ❌ 同様
int o = Integer.parseInt(null);    // ❌ 同様 (Java 8+) または NPE

// 対処: try-catch または事前バリデーション
try {
    int n = Integer.parseInt(s);
} catch (NumberFormatException e) {
    n = 0;   // デフォルト値
}

// Apache Commons NumberUtils なら例外を投げない
int n = NumberUtils.toInt(s, 0);

10. IOException 系

// 検査例外なので try-catch または throws 必須

// ファイル無し
try {
    String txt = Files.readString(Path.of("notfound.txt"));
} catch (NoSuchFileException e) {
    // ファイルが存在しない
} catch (IOException e) {
    // その他の I/O エラー
}

// ネットワーク
try (Socket sock = new Socket("example.com", 80)) {
    // ...
} catch (UnknownHostException e) {
    // DNS 解決失敗
} catch (ConnectException e) {
    // 接続拒否
} catch (SocketTimeoutException e) {
    // タイムアウト
} catch (IOException e) {
    // その他
}

FAQ

Q: 検査例外と非検査例外、どちらを投げるべき?
A: 呼び出し側が回復可能なら検査例外、プログラムバグなら非検査例外。現代のフレームワーク (Spring 等) は非検査例外を好む傾向。

Q: 例外を catch して何もしない (空 catch) は問題?
A: 重大なバグの温床。最低限 log.error("...", e) でログに残してください。

Q: NPE を完全に防ぐ方法は?
A: 完全には不可能ですが、Optional の活用@NonNull / @Nullable アノテーションKotlin への移行で大幅に減らせます。

編集
Post Share
子ページ
  1. java.lang.NoSuchMethodError
  2. java.lang.ClassCastException: java.util.Date cannot be cast to java.sql.Date
  3. java.lang.UnsupportedClassVersionError
  4. version less than X.X is not supported.
  5. パッケージ~は存在しません
  6. org.apache.jasper.JasperException: ...The jsp:param action must not be...
  7. java.io.FileNotFoundException: ファイル名 (許可がありません)
  8. java.sql.SQLException: Cannot convert value 'YYYY-MM-DD ...' from column n(YYYY-MM-DD ...) to TIMESTAMP.
  9. 警告: この文字は、エンコーディング[文字コード]にマップできません
  10. java.text.ParseException: Unparseable date
  11. Unsupported major.minor version 52.0
  12. エンティティ" ... "への参照は';'デリミタで終了する必要があります。
  13. java.math.BigDecimal cannot be cast to java.lang.String
同階層のページ
  1. プラットホーム
  2. 環境構築
  3. 文法
  4. API
  5. Servlet(サーブレット)
  6. JSP
  7. Applet(アプレット)
  8. デザインパターン
  9. フレームワーク
  10. ライブラリ
  11. Androidアプリケーション
  12. Project Jigsaw
  13. エラー一覧
  14. 日付の加算、減算
  15. 文字列の数字チェック
  16. 改行コードの削除
  17. 先頭と末端の文字の削除
  18. warファイルの中身を確認する方法
  19. nullもしくは空文字の判定
  20. beanの中身を確認する方法
  21. org.apache.log4j.Logger のログ出力で printStackTrace() のエラー内容を出力する方法
  22. Javaのバージョン確認方法