在 Java 的方法中抛出特定的异常是多余的吗?

Posted

技术标签:

【中文标题】在 Java 的方法中抛出特定的异常是多余的吗?【英文标题】:Is it redundant to throw specific exception in Java's method? 【发布时间】:2014-08-17 11:55:38 【问题描述】:

考虑以下代码 sn-p。

public static void main(String [] args) throws IOException

    ....

我的假设告诉我:任何异常,无论是arrayOutOfBoundsException 还是IOException,程序都将终止,因为没有捕获异常(并且抛出的异常不是一般性的)。但是我确实看到人们在方法签名处抛出 specific 异常。

我的问题:这样做是多余的吗? (因为任何异常都会导致程序终止)

如果不是多余的,人们这样做的原因是什么?

【问题讨论】:

-1 是没有根据的。这是一个很好的问题。 嘿 :) 我希望你能在对你最有帮助的答案上打勾:D (无耻的我) @ADTC 当然,如果你觉得这个问题有帮助,你也可以投票。 已经完成 :) 您看到 0 是因为有反对意见反对我的赞成意见。 -1+1 = 0 【参考方案1】:

什么捕获了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方法时,您必须处理可能抛出的已检查异常。

【讨论】:

@ADTC “JVM 所做的处理只是在错误流中打印异常的堆栈跟踪,然后自行终止”并不完全正确。 VM 不会因此而终止——它只是终止发生异常的 thread。然后,VM 将终止 如果 没有更多活动的非守护线程。例如,如果您打开了 Frame,则 VM 不会终止,因为 Swing 仍在运行。 (但还是不错的详细答案+1) @Durandal 你说得对!谢谢,我会尽量把它说出来,不要让它太复杂而难以理解。【参考方案2】:

如果main 中的某些代码抛出checked exception(如IOException),您必须throws 中声明它。 main 方法在这方面就像一个普通方法(实际上,它就像一个普通方法在所有方面,除了它也是程序的入口点)。

【讨论】:

程序入口点甚至不是强制性的。启动程序时,您必须指定必须包含具有该签名的方法的主类。如果你不指定一个类作为主类,它不会被用作入口点。 @AndréStannek 是的,我试图保持简单,因为这与问题没有直接关系。但好点;我会改写一下。 @yshavit have to declared it in throws 是什么意思? @user3437460 我的意思是把它添加到throws 子句中,就像throws IOException 一样。如果您不了解这些,您应该阅读已检查与未检查的异常。我在答案中链接到的页面是一个很好的起点,那里有很多更多的材料(包括在 *** 上)。

以上是关于在 Java 的方法中抛出特定的异常是多余的吗?的主要内容,如果未能解决你的问题,请参考以下文章

忽略在 C# .NET 中抛出的特定异常

特定网站在 QWebView 中抛出异常

使用 Mockito 从模拟中抛出已检查的异常

在java web开发中抛出如下异常,求大神知道!

java中抛出异常以及日志

Java:构造函数中抛出异常,我的对象仍然可以创建吗?