JavaのNoClassDefFoundErrorとClassNotFoundExceptionの根本的な相違

Javaアプリケーションの実行時にクラスが見つからない場合、NoClassDefFoundError と ClassNotFoundException という2つの異なる問題に遭遇することがある。いずれもクラスローディングに関するものだが、その性質や発生タイミングには明確な違いが存在する。

NoClassDefFoundError は java.lang.Error のサブクラスであり、JVMが実行時に必要なクラス定義を解決できなかったことを示す。コンパイル時には存在していたクラスが、実行時のクラスパスに含まれていない場合に典型的に発生する。内部的には、クラスローダーが ClassNotFoundException をキャッチした後、それを NoClassDefFoundError にラップしてスローしている。

一方、ClassNotFoundException はチェック例外で、Class.forName() や ClassLoader.loadClass()、findClass() などを用いた明示的なクラスローディング操作でスローされる。アプリケーションコード内でキャッチして処理することが可能だ。

NoClassDefFoundError の発生例

下記のコードはコンパイル時に Google Guava の Maps クラスを参照している。しかし実行時に Guava のJARをクラスパスに含めない場合、JVMは対象クラスをロードできず NoClassDefFoundError をスローする。

import com.google.common.collect.Maps;
import java.util.Map;

public class MapExample {
    public static void main(String[] args) {
        Map<String, Integer> sample = Maps.newHashMap();
        System.out.println(sample.size());
    }
}

コンパイル: javac -cp guava-30.1-jre.jar MapExample.java
誤った実行: java MapExample

この結果、スタックトレースには NoClassDefFoundError: com/google/common/collect/Maps が表示され、その原因として ClassNotFoundException が記録される。これは、JVMがクラス定義を自動的に解決しようとして失敗したものであり、アプリケーション側では直接制御できない。

ClassNotFoundException の発生例

次に、Class.forName() を用いて動的にクラスをロードするケースを示す。ここでは Guava の Lists クラスを指定しているが、クラスパスに当該ライブラリが存在しなければ ClassNotFoundException がスローされる。

public class DynamicLoadSample {
    public static void main(String[] args) {
        try {
            Class<?> target = Class.forName("com.google.common.collect.Lists");
            System.out.println("ロード成功: " + target.getName());
        } catch (ClassNotFoundException ex) {
            System.err.println("クラスが見つかりません: " + ex.getMessage());
        }
    }
}

このコードをライブラリなしでコンパイル・実行すると、ClassNotFoundException が forName() メソッド内から直接スローされる。呼び出し元で捕捉し、適切な代替処理に繋げることも容易である。

NoClassDefFoundError はJVMが静的に参照解決を行う過程で生じる致命的エラーであり、ClassNotFoundException はプログラマが明示的に実行する動的ロード操作に伴う例外である。これらの違いを理解しておくことで、クラスパス設定の不備や依存関係の欠落に起因するトラブルシューティングの初動が格段に早くなる。

タグ: Java NoClassDefFoundError ClassNotFoundException ClassLoader JVM

10月3日 00:38 投稿