Java

[Java] ClassNotFoundException VS NoClassDefFoundError

에드박 2021. 8. 27. 22:40

런타임에 JVM에서 요청한 클래스가 classpath에 없을 때 ClassNotFoundException, NoClassDefFoundError가 발생할 수 있습니다.

두 가지 예외는 비슷해보이지만 차이가 있습니다.


ClassNotFoundException

애플리케이션이 클래스의 이름(정규화된 이름)으로 클래스 로드를 시도했을 때 classpath에서 해당 클래스를 찾을 수 없을 때 발생하는 예외입니다. 주로 Class.forName(), ClassLoader.loadClass(), ClassLoader.findSystemClass() 를 사용하여 클래스를 로드하려 할 때 발생합니다. 제 경우엔 의존성을 추가하지 않은 상태로 해당 의존성에 포함된 클래스를 로드하려고 할 때 자주 마주하는 예외입니다.

 

리플렉션 작업 시 ClassNotFoundException 예외에 주의해야합니다.

가끔 두개의 클래스 로더가 있고 다른 클래스 로더에 의해 로드된 클래스에 접근하려고 하면 발생합니다.

 

아래의 예시에서 처럼 "Charlie" 라는 이름의 클래스가 없으면 ClassNotFoundException 예외가 발생합니다!

 

    @Test
    void test() throws ClassNotFoundException {
        Class.forName("Charlie");
    }


NoClassDefFoundError

 

아래와 같은 상황에서 발생할 수 있습니다.

  • new 연산자로 클래스를 인스턴스화
  • 메소드 호출로 클래스 로드

컴파일러는 성공적으로 컴파일을 진행했지만 런타임에 클래스 파일을 찾을 수 없을 때 발생합니다.

보통 static 초기화 블록 또는 static 필드를 초기화하다가 예외가 발생하여 클래스 초기화에 실패한 경우에 자주 발생합니다.

 

에러가 발생하는 예외 상황은 아래와 같습니다.

Charlie 라는 클래스는 test라는 static 필드를 가지는데 1을 0으로 나누는 연산에서 예외가 발생합니다. 즉 static 필드를 초기화하다가 예외가 발생하여 클래스 초기화에 실패한 것입니다.

클래스 초기화에 실패하는 순간에는 java.lang.ExceptionInInitializerError 에러가 발생합니다. 이후에 다시한번 Charlie 클래스를 인스턴스화 하려고하면 NoClassDefFoundError가 발생합니다.

 

class Charlie {
    static int test = 1 / 0;
}

class NoClassDefFoundErrorExample {
    public Charlie run() {
        Charlie charlie;

        try {
            charlie = new Charlie(); // java.lang.ExceptionInInitializerError 발생
        } catch (Throwable t) { 
            System.out.println(t);
        }
        charlie = new Charlie(); // NoClassDefFoundError 발생
        return charlie;
    }
}

두 가지 예외가 발생 시 체크해봐야 하는 것

  • 해당 클래스를 사용하는 클래스 또는 jar의 classpath가 유효한지 확인합니다.
  • 애플리케이션의 classpath가 유효하게 설정됐는지 확인합니다. (유효하지 않다면 애플리케이션의 classpath를 정확하게 등록해야합니다.)
  • ClassNotFoundException에서 설명했듯이 두개의 클래스 로더가 있고 다른 클래스 로더에 의해 로드된 클래스에 접근하려고 하면 발생합니다.

 


참고자료