如果NoClassDefFoundError是由ClassNotFoundException引起的,为什么Java期望你捕获两个throwable?

时间:2013-04-02 01:39:38

标签: java exception error-handling throwable

当我运行此代码时,应用程序以ClassNotFoundException退出:

//uncaught ClassNotFoundException
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
}
catch (NoClassDefFoundError e)
{
}

当我尝试编译此代码时,编译器会抱怨ClassNotFoundException无法访问,因为它不会从try-catch语句的try-clause中抛出。

//Won't compile
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
}
catch (ClassNotFoundException e)
{
}

当我运行此代码时,唯一被捕获的throwable是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

5 个答案:

答案 0 :(得分:12)

所以,你误解了你的堆栈跟踪。

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类的属性,并且在打印堆栈跟踪时,Java将显示有关直接异常及其根本原因的信息。更难说为什么define方法在内部失败,但有一点是肯定的 - 你不能在包名中使用关键字package

答案 1 :(得分:5)

找到类的.class时会发生NoClassDefFoundError,但无法从该.class构造类。

通常会出现几种不同的情况,加上一些比较模糊的情景。

  • .class文件包含与类文件名/包
  • 不匹配的名称(和包)
  • 无法找到验证和初始化类所需的类
  • 课程初始化期间发生错误

在大多数情况下,先前发生的另一个错误或异常会被类加载器捕获,并且会发出新错误信号。

目前尚不清楚上述异常追踪中究竟出现了哪种情况,但我猜测某种名称不匹配。

答案 2 :(得分:1)

NoClassDefFoundError实际上是Error的子类,不应该捕获它们。有关详细信息,请参阅docs of Error。以下重要提示:

  

错误是Throwable的子类,表示严重问题   一个合理的应用程序不应该试图抓住。最多的   错误是异常情况。

     

不需要在throws子句中声明任何方法   在执行期间可能抛出的Error的子类   方法但没有捕获,因为这些错误是异常情况   永远不应该发生。

出于这个原因,我认为你应该仔细看看你的代码,看看你做错了什么。

答案 3 :(得分:0)

//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(),你会看到类似的输出。

答案 4 :(得分:-1)

正如已经指出的那样,Java不允许你处理错误。

无论如何,我不确定你试图解决这些异常(和错误)的原因是什么,但这些都是程序员并不需要担心的事情(大多数时候)。对我而言,这是您的代码/项目中其他地方存在问题的症状。如果系统抛出一个ClassNotFoundException,它允许你抓住它,你将如何处理它?或者您是否愿意解决应用程序所需的某个类不在类路径中的实际问题?

另外,您可能需要查看difference between NoClassDefFoundError and ClassNotFoundException以更好地解决问题。