JVM如何处理main方法抛出的异常?


10

我了解异常,将其抛出,处理它们,并将其传播到调用堆栈中较低的方法(即throws)。

我不明白的是:

public static void main(String[] args) throws Exception {
    ...
}

现在,我假设main抛出的情况下,ExceptionJVM将对其进行处理(对吗?)。如果是这样,那么我的问题是:

JVM如何处理引发的异常main?它有什么作用?

Answers:


19

您可能会认为public static void mainJava 中的方法或mainC中的函数是程序的真正入口点,但事实并非如此。所有高级语言(包括C)都具有语言运行时,该运行时会初始化程序,然后将控制流转移到入口点。对于Java,初始化将包括:

  • 设置JVM
  • 加载所需的类
  • 运行静态初始化程序块。这可以在main调用之前执行用户定义的代码。这些块不应该引发异常。

有多种方法可以实现异常处理,但是出于这个问题的目的,它们都可以看作黑盒子。但是重要的是,语言运行时必须始终提供最外部的异常处理程序,以捕获用户代码未捕获的所有异常。该异常处理程序通常将打印出堆栈跟踪,以有序的方式关闭程序,并以错误代码退出。正确关闭程序包括破坏对象图,调用终结器以及释放诸如内存,文件句柄或网络连接之类的资源。

为了说明起见,您可以对运行时进行映像处理,将所有代码包装在一个看起来像

try {
    loadClasses();
    runInitializers();
    main(argv);
    System.exit(0);
} catch (Throwable e) {
    e.printStackTrace();
    System.exit(-1);
}

除了一种语言不必实际执行这样的代码外。可以在throw搜索第一个适用的异常处理程序的代码(或等效代码)中实现相同的语义。


9

所有Java代码都在线程上下文中运行。链接的JavaDoc解释了错误处理和退出条件,但这是要点:

  • JVM自行启动并准备执行环境。
  • JVM创建一个线程,该线程将main()使用任何适用的命令行参数来运行该方法。
  • JVM设置了一个默认的未捕获异常处理程序,该异常处理程序将异常打印为标准错误并终止。
  • JVM执行线程。

在未捕获的异常的情况下,该程序会根据以上第三项有效地死亡。Java语言规范的第11.3节中进一步指定了此行为。


附加信息

其他人提到静态块以及它们之前如何执行main()。但是,这需要更多的解释才能正确理解。

当加载一个类,类加载器必须初始化所有static final状态和运行所有static之前的类都可以使用,以包括类(除了的实例实例:创建其中一类恒定在静态块初始化一个Java类之后创建类的实例,构造函数引用常量。但是,这一切在类加载器逻辑中发生,然后任何代码都可以引用该类。此外,该类会在引用该类的任何线程中加载。

这意味着如果包含的类main()引用了另一个类(例如,类常量),则必须main()执行该类之前加载该类以包含其静态块。否则,将按上述方式执行静态块。如果无法加载该类,则包含该类的类main()也将无法加载,程序将终止。

仅供参考:静态块可以抛出。Errors按原样抛出。Exceptions被禁止(编译时错误)。RuntimeExceptions被包装在ExceptionInInitializerError中。这些都是每个未捕获异常处理程序,它通常要么杀死线程或应用程序(主线程),除非你仔细包裹在一个类的引用(和加载)处理try- catch

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.