ClassNotFoundException vs NoClassDefFoundError

ClassNotFoundException vs NoClassDefFoundError

1. Вступление

ИClassNotFoundException, иNoClassDefFoundError возникают, когда JVM не может найти запрошенный класс в пути к классам. Хотя они выглядят знакомо, между ними есть некоторые принципиальные различия.

В этом руководстве мы обсудим некоторые причины их возникновения и способы их устранения.

2. ClassNotFoundExceptionс

ClassNotFoundException - это проверенное исключение, которое возникает, когда приложение пытается загрузить класс через его полное имя и не может найти его определение в пути к классам.

Это происходит в основном при попытке загрузить классы с использованиемClass.forName(),ClassLoader.loadClass() илиClassLoader.findSystemClass(). Следовательно, нам нужно быть особенно осторожными сjava.lang.ClassNotFoundException при работе с отражением.

Например, давайте попробуем загрузить класс драйвера JDBC без добавления необходимых зависимостей, что даст намClassNotFoundException:

@Test(expected = ClassNotFoundException.class)
public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException()
  throws ClassNotFoundException {
      Class.forName("oracle.jdbc.driver.OracleDriver");
}

3. NoClassDefFoundErrorс

NoClassDefFoundError - фатальная ошибка. Это происходит, когда JVM не может найти определение класса при попытке:

  • Создайте экземпляр класса с помощью ключевого словаnew

  • Загрузить класс с помощью вызова метода

Ошибка возникает, когда компилятор может успешно скомпилировать класс, но среда выполнения Java не может найти файл класса. Обычно это происходит, когда возникает исключение при выполнении статического блока или инициализации статических полей класса, поэтому инициализация класса завершается неудачно.

Давайте рассмотрим сценарий, который представляет собой простой способ воспроизвести проблему. ИнициализацияClassWithInitErrors вызывает исключение. Итак, когда мы пытаемся создать объектClassWithInitErrors,, он выдаетExceptionInInitializerError.

Если мы попытаемся снова загрузить тот же класс, мы получимNoClassDefFoundError:

public class ClassWithInitErrors {
    static int data = 1 / 0;
}
public class NoClassDefFoundErrorExample {
    public ClassWithInitErrors getClassWithInitErrors() {
        ClassWithInitErrors test;
        try {
            test = new ClassWithInitErrors();
        } catch (Throwable t) {
            System.out.println(t);
        }
        test = new ClassWithInitErrors();
        return test;
    }
}

Давайте напишем контрольный пример для этого сценария:

@Test(expected = NoClassDefFoundError.class)
public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() {

    NoClassDefFoundErrorExample sample
     = new NoClassDefFoundErrorExample();
    sample.getClassWithInitErrors();
}

4. разрешение

Иногда диагностика и устранение этих двух проблем может занимать довольно много времени. Основной причиной обеих проблем является недоступность файла класса (в пути к классам) во время выполнения.

Давайте рассмотрим несколько подходов, которые мы можем рассмотреть при работе с любым из них:

  1. Нам нужно убедиться, что класс или jar, содержащие этот класс, доступны в classpath. Если нет, нам нужно добавить его

  2. Если он доступен в пути к классам приложения, то, скорее всего, путь к классам переопределяется. Чтобы это исправить, нам нужно найти точный путь к классу, используемый нашим приложением.

  3. Кроме того, если приложение использует несколько загрузчиков классов, классы, загруженные одним загрузчиком классов, могут быть недоступны другим загрузчикам классов. Чтобы устранить неисправность, важно знатьhow classloaders work in Java

5. Резюме

Хотя оба эти исключения связаны с тем, что путь к классам и среда выполнения Java не могут найти класс во время выполнения, важно отметить их различия.

Среда выполнения Java выдаетClassNotFoundException при попытке загрузить класс только во время выполнения, а имя было предоставлено во время выполнения. В случаеNoClassDefFoundError, the класс присутствовал во время компиляции, но среда выполнения Java не смогла найти его в пути к классам Java во время выполнения.

Как всегда, полный код для всех примеров можно найти вover on GitHub.