为什么在调用函数时需要“抛出异常”?


97
class throwseg1
{
    void show() throws Exception
    {
        throw new Exception("my.own.Exception");
    }

    void show2() throws Exception  // Why throws is necessary here ?
    {
        show();
    }

    void show3() throws Exception  // Why throws is necessary here ?
    {
        show2();
    }

    public static void main(String s[]) throws Exception  // Why throws is necessary here ?
    {
        throwseg1 o1 = new throwseg1();
        o1.show3();
    }
}

为什么编译器报告方法show2()show3()以及main()具有

未报告的异常必须捕获​​或声明为引发的异常

当我throws Exception从这些方法中删除时?


2
当然可以声明@PaulTomblin main引发Exception。如果是这样,JVM将关闭。正如编译器所允许的那样,这几乎无视它。
塔蒙(Taymon)2012年

当被调用的方法(Methdod1)抛出时Exception,我们必须用定义调用方法(Method2throws Exception; 如果我们不在调用方法中处理该异常。这样做的目的是为了给抬起头调用方法(方法3)的方法2,一个异常可能抛出方法2,你应该在这里处理它,否则它可能会中断你的程序。
Rito

同样,如果Method3在主体中未处理异常,则必须throws Exception在其方法定义中进行定义以放弃其调用方法。先前评论的扩展
Rito

Answers:


144

您可能知道,在Java中,异常可以分为两种:一种需要throws子句,或者如果您不指定一个则必须处理,而另一种不需要。现在,请参见下图:

在此处输入图片说明

在Java中,您可以抛出任何扩展Throwable类的内容。但是,您不需要throws为所有类都指定一个子句。具体地,类,或者是一个ErrorRuntimeException或任何这些的两个子类。您的情况Exception不是Error或的子类RuntimeException。因此,它是一个已检查的异常throws,如果不处理该特定异常,则必须在子句中指定该异常。这就是为什么您需要该throws子句的原因。


Java教程

例外是在程序执行期间发生的事件,该事件中断了程序指令的正常流程。

现在,众所周知,异常分为两类:已检查和未检查。为什么要进行这些分类?

已检查的异常:它们用于表示在程序执行期间可以恢复的问题。它们通常不是程序员的错。例如,用户指定的文件不可读,或者没有可用的网络连接,等等。在所有这些情况下,我们的程序都不需要退出,而是可以采取措施,例如提醒用户或进入后备状态机制(例如在网络不可用时脱机工作)等

未检查的异常:它们又可以分为两种:错误和RuntimeException。之所以要取消选中它们,原因之一是它们的数量众多,并且要求处理它们全部都将使我们的程序混乱,并降低其清晰度。另一个原因是:

  • 运行时异常:它们通常是由于程序员的错误而发生的。例如,如果ArithmeticException发生零除或ArrayIndexOutOfBoundsException发生,这是因为我们在编码时不够谨慎。它们之所以发生,通常是因为我们程序逻辑中的某些错误。因此,在我们的程序进入生产模式之前必须清除它们。从某种意义上说,它们不受检查,即程序在发生时必须失败,以便我们的程序员可以在开发和测试时自行解决。

  • 错误:错误是通常无法从中恢复程序的情况。例如,如果StackOverflowError发生a ,我们的程序将无法做很多事情,例如增加程序的函数调用堆栈的大小。或者,如果OutOfMemoryError发生这种情况,我们不能做太多事情来增加程序可用的RAM数量。在这种情况下,最好退出程序。这就是为什么使它们不受控制。

有关详细信息,请参阅:


我从您的答案中得到的是Error类及其子类和RuntimeException类及其子类,它们都处于未经检查的异常下(例如System.out.println(5/0);无需抛出,因为它是运行时异常,但仍可以应用try catch),并且检查了Exception类,因此我们需要在该方法和调用该方法的每个方法中声明throws子句
nr5 2012年

还有一个问题:是否将异常分类为未检查和检查的异常,特别是未检查的异常(运行时错误),以避免在编译期间出现更多错误?
nr5 2012年

@Jomoos-假设方法中的代码引发IOException。然后,可以在方法的声明中放入“ throws Exception”吗?
MasterJoe

哦。我明白了 例外层次结构的规则存在例外。制造。完善。感。谢谢Java。
JJS

25

Java要求您处理或声明所有异常。如果您不使用try / catch块处理异常,则必须在方法的签名中声明该异常。

例如:

class throwseg1 {
    void show() throws Exception {
        throw new Exception();
    }
}

应写为:

class throwseg1 {
    void show() {
        try {
            throw new Exception();
        } catch(Exception e) {
            // code to handle the exception
        }
    }
}

这样,您可以摆脱方法声明中的“ throws Exception”声明。


7
不是的子类的所有异常RuntimeException
yshavit 2012年

是否还有其他类似Exception这样的类被检查?
nr5 2012年

1
你什么意思?由于所有异常对象都将“ Exception”作为其基类,因此,如果您捕获到“ Exception”对象(例如在我的示例中),它将捕获所有抛出的异常。更具体地说(由于不同的异常可能需要不同的处理方式),您应该有多个catch块。
jebar8'7

如果我要说的是检查异常需要在编译时处理并在运行时捕获。我对吗 ?如果是的话,将未经检查的异常改为相同的句子?
nr5 2012年

@ jebar8-您将Java与.NET混淆了-在Java中,throwables必须继承Throwable(继承Exception也可以,因为它可以扩展Throwable,但不是必需的)。
BrainSlugs83

4

Exception是一个检查异常类。因此,任何调用声明该方法的方法的代码都throws Exception必须对其进行处理或声明。


声明链中的每个方法都将引发Exception,包括main。那么问题出在哪里呢?
Paul Tomblin

@PaulTomblin im询问为什么在调用函数中必须编写引发异常,从而调用引发异常的函数
nr5 2012年

好的,我不明白您为什么要询问实际上不是从发布的代码中得到的编译器错误。这是一种奇怪的询问方式。
Paul Tomblin

4

throws Exception声明是跟踪的可能抛出的预料之中,但不可避免的理由例外方法的自动化的方式。该声明通常特定于可能引发的异常类型,例如throws IOExceptionthrows IOException, MyException

我们所有人都有或将最终编写出意外停止的代码,并报告由于运行程序之前未曾预料到的异常而导致的异常,例如被零除或索引超出范围。由于该方法无法预料到错误,因此无法“捕获”并使用try catch子句对其进行处理。该方法的任何毫无戒心的用户也不会知道这种可能性,并且他们的程序也将停止。

当程序员知道某些类型的错误可能发生,但想在方法之外处理这些异常时,该方法可以将一种或多种类型的异常“抛出”给调用方法,而不是处理它们。如果程序员未声明该方法(可能)抛出异常(或者Java没有能力声明该异常),则编译器将无法知道,并且该方法的未来用户将自行决定,捕获并处理该方法可能引发的任何异常。由于程序可以具有由许多不同程序编写的多层方法,因此很难(不可能)跟踪哪些方法可能引发异常。

即使Java具有声明异常的能力,您仍然可以编写具有未处理和未声明的异常的新方法,并且Java将对其进行编译,并且您可以运行它并希望取得最佳效果。Java不允许您执行的操作是编译新方法(如果该方法使用了已声明为抛出异常的方法),除非您在方法中处理了已声明的异常或声明您的方法抛出相同的异常异常,或者如果有多个异常,则可以处理一些异常并抛出其余异常。

当程序员声明该方法引发特定类型的异常时,它只是一种自动方式,向使用该方法的其他程序员警告可能出现异常。然后,程序员可以通过声明调用方法也抛出相同的异常来决定处理该异常或传递警告。由于已警告编译器该新方法中可能存在异常,因此它可以自动检查新方法的未来调用者是否处理该异常或声明该异常并强制一个或另一个发生。

关于这种解决方案的好处是,当编译器报告时,Error: Unhandled exception type java.io.IOException它给出了声明为引发异常的方法的文件和行号。然后,您可以选择简单地传递责任,并声明您的方法也“引发IOException”。可以一直执行到主方法,然后再使主方法停止并向用户报告异常。但是,最好以一种不错的方式捕获异常并对其进行处理,例如向用户解释发生了什么以及如何解决它。当方法确实捕获并处理了异常时,它不再需要声明异常。可以这么说。


0
package javaexception;


public class JavaException {
   void show() throws Exception
    {
        throw new Exception("my.own.Exception");
    }

void show2() throws Exception  // Why throws is necessary here ?
{
    show();
}

void show3() throws Exception  // Why throws is necessary here ?
{
    show2();
}
public static void main(String[] args) {

   JavaException a = new JavaException();

   try{
   a.show3();
   }catch(Exception e){
       System.out.println(e.getMessage());
   }
}

您的程序只有很小的变化。在主要问题上,很多人似乎都误解了,每当您抛出异常时就需要处理它,而不必在同一位置处理(例如程序中的show1,2,3方法),但是必须首先使用调用者方法在“主要”内部。一言以蔽之,即使发生异常的方法不一样,也必须有“捕获/尝试”的“抛出”。


0
void show() throws Exception
{
    throw new Exception("my.own.Exception");
}

由于show()方法中存在已检查的异常,该方法未处理该异常,因此我们使用throws关键字传播异常。

void show2() throws Exception //Why throws is necessary here ?
{
show();
}

由于您在show2()方法中使用show()方法,并且已传播了异常,因此您应该在此处进行处理。如果您在此处未处理Exception,那么您将使用throws关键字。因此,这就是在方法签名处使用throws关键字的原因。



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.