【问题标题】:Why is "throws Exception" necessary when calling a function?为什么调用函数时需要“抛出异常”?
【发布时间】:2012-07-20 07:37:28
【问题描述】:
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 时?

【问题讨论】:

  • @PaulTomblin main 当然可以声明抛出异常。如果是这样,JVM 将关闭。这几乎是编译器允许的忽略它。
  • 当被调用方法(Methdod1)抛出Exception时,我们要定义调用方法(Method2)为throws Exception;如果我们没有在调用方法中处理该异常。这样做的目的是提醒 Method2 的调用方法(Method3),Method2 可能会抛出异常,您应该在这里处理它,否则它可能会中断你的程序。
  • 类似地,如果 Method3 没有在其主体中处理异常,则它必须在其方法定义中定义throws Exception 以提示其调用方法。 上一条评论的扩展

标签: java exception-handling unhandled-exception throws checked-exceptions


【解决方案1】:

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

在 Java 中,您可以抛出任何扩展 Throwable 类的东西。但是,您不需要为所有类指定 throws 子句。具体来说,是 ErrorRuntimeException 或这两者的任何子类的类。在您的情况下,Exception 不是ErrorRuntimeException 的子类。因此,这是一个检查异常,如果您不处理该特定异常,则必须在 throws 子句中指定。这就是您需要throws 子句的原因。


来自Java Tutorial

异常是在程序执行期间发生的事件,它会破坏程序指令的正常流程。

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

Checked Exception:它们用于表示在程序执行过程中可以恢复的问题。它们通常不是程序员的错。例如,用户指定的文件不可读,或没有可用的网络连接等,在所有这些情况下,我们的程序都不需要退出,而是可以采取诸如警告用户之类的操作,或者进入回退机制(如网络不可用时离线工作)等。

Unchecked Exceptions: 它们又可以分为两种:Errors 和 RuntimeExceptions。不检查它们的一个原因是它们数量众多,并且需要处理所有这些会使我们的程序混乱并降低其清晰度。另一个原因是:

  • 运行时异常:它们通常是由于程序员的错误而发生的。例如,如果出现被零除的ArithmeticException 或出现ArrayIndexOutOfBoundsException,那是因为我们在编码时不够仔细。它们的发生通常是因为我们的程序逻辑中的一些错误。因此,必须在我们的程序进入生产模式之前清除它们。它们是未经检查的,因为我们的程序在发生时必须失败,以便我们程序员可以在开发和测试时自行解决它。

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

详细信息见:

【讨论】:

  • 我从你的回答中得到的是 Error 类及其子类和 RuntimeException 类及其子类,它们属于未经检查的异常(如 System.out.println(5/0); 有不需要抛出,因为它是一个运行时异常,但我们仍然可以应用 try catch) 并且检查 Exception 类,因此我们需要在该方法和调用它的每个方法中声明 throws 子句
  • 还有一个问题:如果异常分为未检查和检查,特别是未检查的(运行时错误)以避免编译时出现更多错误?
  • @Jomoos - 假设方法内的代码抛出 IOException。那么,在方法的声明中加入“throws Exception”可以吗?
  • 哦。我现在明白了。异常层次结构的规则有一个例外。使。完美的。感觉。感谢 Java。
【解决方案2】:

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
        }
    }
}

这样可以去掉方法声明中的“抛出异常”声明。

【讨论】:

  • 所有不是RuntimeException子类的异常,即。
  • 如果有任何其他类如 Exception 被检查?
  • 什么意思?由于所有异常对象都将“异常”作为其基类,因此如果您捕获“异常”对象(如我的示例中),它将捕获任何抛出的异常。更具体地说(因为不同的异常可能需要不同的处理方式)你应该有多个 catch 块。
  • 如果我说检查的异常需要在编译时处理并在运行时捕获。我对吗 ?如果是,那么为 Unchecked exception 表达相同的句子将是?
  • @jebar8 -- 您将 Java 与 .NET 混淆了 -- 在 Java 中,throwables 必须继承 Throwable(继承 Exception 也可以,因为它扩展了 Throwable,但这不是必需的)。
【解决方案3】:

throws Exception 声明是一种自动跟踪可能由于预期但不可避免的原因引发异常的方法的方法。声明通常具体说明可能引发的异常类型,例如 throws IOExceptionthrows IOException, MyException

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

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

即使 Java 具有声明异常的能力,您仍然可以编写一个带有未处理和未声明异常的新方法,Java 会编译它,您可以运行它并希望获得最好的结果。 Java 不会让你做的是编译你的新方法,如果它使用一个被声明为抛出异常的方法,除非你在你的方法中处理声明的异常或者声明你的方法抛出相同的异常或者如果有多个异常,您可以处理一些并抛出其余的。

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

这种解决方案的好处在于,当编译器报告Error: Unhandled exception type java.io.IOException 时,它会给出声明抛出异常的方法的文件和行号。然后,您可以选择简单地推卸责任并声明您的方法也“抛出 IOException”。这可以一直执行到 main 方法,然后它会导致程序停止并向用户报告异常。但是,最好捕获异常并以一种很好的方式处理它,例如向用户解释发生了什么以及如何修复它。当方法确实捕获并处理异常时,它不再需要声明异常。可以说,降压就止步于此了。

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 链中的每个方法都被声明为抛出异常,包括main。那么问题出在哪里?
    • @PaulTomblin 我在问为什么有必要在调用函数中编写抛出异常,调用一个抛出异常的函数
    • 好的,我不明白您为什么要询问您实际上不是从您发布的代码中得到的编译器错误。这是一种奇怪的提问方式。
    【解决方案5】:
    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 方法),但你必须首先调用方法在“主要”内部。一言以蔽之,有'throw',必有'catch/try',即使发生异常的方法不同。

    【讨论】:

      【解决方案6】:
      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 关键字的原因。

      【讨论】:

        【解决方案7】:

        基本上,如果您没有在抛出异常的地方处理异常,那么您可以在函数定义处使用“抛出异常”。

        【讨论】:

          【解决方案8】:

          如果您通过在当前方法的签名中声明 throws 指令来传播异常,则必须使用 try/catch 构造来处理异常。

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-08
          • 1970-01-01
          • 1970-01-01
          • 2020-06-13
          • 1970-01-01
          • 2011-12-12
          相关资源
          最近更新 更多