什么捕获了main方法抛出的异常?
程序将被终止,因为没有捕获异常
看起来可能是这样,因为main 方法是你的程序开始的地方。但实际上,Java 虚拟机 (JVM) 调用 main 方法,因此从技术上讲,它会捕获并处理它抛出的任何异常。
JVM 所做的处理只是在错误流中打印异常的堆栈跟踪,然后终止您的程序*。这就是为什么您会在程序终止之前在控制台中看到堆栈跟踪(除非错误流被重定向到其他地方,例如文件)。
* 如果 JVM 中没有运行其他程序(例如实时非守护线程),它也会自行终止。
为什么要声明?
但是我确实看到人们在方法签名处抛出了特定的异常。
这样做是多余的吗? (因为任何异常都会导致程序终止)
首先,我要澄清的是,写throws,程序员不是抛出异常。程序员只是声明该方法可能会抛出此异常,并且该方法的调用者必须以某种方式处理它。
以你为例:
public static void main(String [] args) throws IOException
这很可能是程序员添加的,因为他的程序调用了另一个类的某个方法,该类也声明了这个。一些常见的例子是:
public FileWriter(String fileName) throws IOException // a constructor can also throw exceptions
FileWriter.write(int c) throws IOException
此FileWriter 类的设计者已强制其用户(程序员)处理IOException。这称为已检查异常。
两种类型的异常
经过检查的异常告诉用户,在程序运行期间,导致此异常的场景很可能会发生即使它通常不应该发生(因为我们不会' t 生活在一个理想的世界中)。这表明存在环境错误,即使在最好的程序中也会抛出这样的异常。
另一种类型的异常是未经检查的异常。您不使用throws 声明NullPointerException(未经检查的异常)的原因是因为导致它的场景预计不会在正常程序运行期间发生。如果发生这种情况,则表明编程错误和编写错误的程序。
如何处理异常?
有两种方法可以处理方法中收到的异常。
首先是程序员在您的示例中所做的方式。只需将该异常返回给调用者即可。
其次是使用try-catch块在内部处理它:
public static void main (String [] args) // no need to declare "throws IOException"
{
try {
/* some code here that may throw IOException */
} catch (IOException ioe) {
System.err.println("Uhhhh something went wrong!");
// or some logging can happen
ioe.printStackTrace();
System.exit(-6); // a custom error signal can be sent in termination
}
}
但又是为什么?
如果不是多余的,人们这样做的原因是什么?
他们这样做是因为 Java 强制明确处理已检查的异常,而可以不处理未检查的异常。
正如我已经解释了处理异常的两种方式,应该注意的是,程序员可能会根据情况选择一种方式而不是另一种方式。对于某些方法,将捕获的异常抛出给调用者可能更有意义,而对于其他方法,在内部处理捕获的异常可能更有意义。
还有一些懒惰的程序员,他们只是用throws 声明每个检查的异常。
注意事项
可以使用上述两种方式中的任何一种来处理已检查和未检查的异常。未经检查的异常为您提供了不处理它的第三种选择,这反过来又让调用者选择处理或不处理它。
如果您使用throws 声明未经检查的异常,它将成为您方法调用者的检查异常。
您也可以混合搭配两种方式。例如,您可以在方法的任何一点内部处理已检查的异常,即使它被声明为在方法签名中抛出。 throws 声明只会在内部未处理已检查异常的情况下生效。
类的main 方法可以像程序中的任何其他常规静态方法一样调用,只需传入一个String 参数数组即可。仅在类作为 Java 程序启动时 JVM 调用此方法的意义上是特殊的。当您手动调用main方法时,您必须处理可能抛出的已检查异常。