Если NoClassDefFoundError вызван ClassNotFoundException, почему Java ожидает, что вы поймаете оба комбайна?
Когда я запускаю этот код, приложение выходит из ClassNotFoundException:
//uncaught ClassNotFoundException
try
{
Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
table.put(clazz.getName(), clazz);
}
catch (NoClassDefFoundError e)
{
}
Когда я пытаюсь скомпилировать этот код, компилятор жалуется, что исключение ClassNotFoundException недоступно, потому что оно не выбрано из try-предложения инструкции try-catch.
//Won't compile
try
{
Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
table.put(clazz.getName(), clazz);
}
catch (ClassNotFoundException e)
{
}
Когда я запускаю этот код, единственное, что можно поймать, это NoClassDefFoundError.
//catches throwable of type java.lang.NoClassDefFoundError,
//with a java.lang.ClassNotFoundException as its cause
try
{
Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
table.put(clazz.getName(), clazz);
}
catch (Throwable e)
{
System.out.println(e.getClass().getName());
System.out.println(e.getCause().getClass().getName());
}
Следующий код скомпилирует и поймает ошибку (и только ошибку), но это неуклюже:
//possible workaround
try
{
Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
table.put(clazz.getName(), clazz);
if (1 == 0) throw new ClassNotFoundException(); // we want the code to compile
}
catch (ClassNotFoundException e)
{
System.out.println("ex");
}
catch (NoClassDefFoundError e)
{
System.out.println("err");
}
И все же, когда я пишу следующее, я могу уйти без предложения catch для причины ошибки:
//and yet this works just fine...
try
{
throw new Error(new IOException());
}
catch (Error e)
{
System.out.println("err");
}
Пример 3 привел бы к заключению, что throwable был NoClassDefFoundError.
Пример 1 привел меня к выводу, что throwable является ClassNotFoundException.
И все же, пример 2 показывает, что java даже не позволяет мне писать код, чтобы правильно поймать ClassNotFoundException.
Просто, когда я собирался сделать вывод о том, что проблема заключается в ошибке, вызванной ошибкой, я запустил код, показанный в предыдущем примере, который показывает, что это не правило.
Может кто-нибудь объяснить, что здесь происходит?
PS: это трассировка стека:
java.lang.NoClassDefFoundError: com/my/pckage/MyClass
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
at Main$MyClassLoader.getClasses(Main.java:78)
at Main.main(Main.java:109)
Caused by: java.lang.ClassNotFoundException: com.my.pckage.MyClass
at java.lang.ClassLoader.findClass(ClassLoader.java:522)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 4 more
Ответы
Ответ 1
Итак, вы неправильно понимаете свою трассировку стека.
java.lang.NoClassDefFoundError: com/my/package/MyClass
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
at Main$MyClassLoader.getClasses(Main.java:78)
at Main.main(Main.java:109)
Caused by: java.lang.ClassNotFoundException: com.my.package.MyClass
Ваш код генерирует NoClassDefFoundError
. основная причина - ClassNotFoundException
. Помните, что cause
является свойством класса Throwable и что при печати stacktraces Java отображает информацию как по прямому исключению, так и по его основной причине. Сложнее сказать, почему метод define
терпит неудачу внутри, но одно можно сказать наверняка - вы не можете использовать ключевое слово package
в имени пакета.
Ответ 2
NoClassDefFoundError возникает, когда класс .class для класса найден, но класс не может быть создан из этого .class.
Существует несколько различных сценариев, которые обычно встречаются, плюс несколько более неясных.
- Файл .class содержит имя (и пакет), которое не соответствует имени/пакету файла класса
- Не удалось найти класс, необходимый для проверки и инициализации класса.
- Произошла ошибка во время инициализации класса
В большинстве этих сценариев есть еще одна ошибка или исключение, которое происходит раньше, улавливается загрузчиком классов, и появляется новая ошибка.
Непонятно, какой именно сценарий происходит в предыдущей трассировке исключения, но я угадываю, что такое несоответствие имени.
Ответ 3
NoClassDefFoundError
на самом деле является подклассом Error
, и они не должны быть пойманы. Подробнее см. docs of error. Важное примечание ниже:
Ошибка - это подкласс Throwable, который указывает на серьезные проблемы что разумное приложение не должно пытаться поймать. Большинство таких ошибки являются ненормальными условиями.
Не требуется метод объявлять в своей брошюре пункт any подклассы ошибки, которые могут быть выброшены во время выполнения но не пойманы, поскольку эти ошибки являются ненормальными условиями, которые никогда не должно происходить.
По этой причине, я думаю, вы должны более внимательно посмотреть на свой код, чтобы увидеть, что вы делаете неправильно.
Ответ 4
//and yet this works just fine...
try
{
throw new Error(new IOException());
}
catch (Error e)
{
System.out.println("err");
}
Замените его:
//and yet this still works fine...
try
{
throw new NoClassDefFoundError(new ClassNotFoundException());
}
catch (Error e)
{
System.out.println("err");
}
Попробуйте e.printStackTrace(), и вы увидите аналогичный вывод.
Ответ 5
Как уже указывалось, Java не позволит вам обрабатывать ошибки.
Во всяком случае, я не совсем уверен, в чем ваши причины пытаются обойти эти исключения (и ошибки), но это те случаи, о которых программистам действительно не нужно беспокоиться (в большинстве случаев). Для меня это симптом, что в вашем коде/проекте есть проблема. Если система выбрасывает ClassNotFoundException
, и это позволяет вам ее поймать, как бы вы справились? Или вы скорее рассмотрите фактическую проблему, что определенный класс, требуемый вашим приложением, не находится в пути к классам?
Кроме того, вы можете проверить разницу между NoClassDefFoundError и ClassNotFoundException, чтобы лучше решить вашу проблему.