【问题标题】:Declaring checked exception using throws clause that is never thrown in the body of the method使用从未在方法主体中抛出的 throws 子句声明检查的异常
【发布时间】:2021-03-02 08:06:51
【问题描述】:

我了解在相应的 try 块中捕获从未抛出的已检查异常是无效的。因为如果异常发生,编译器本身会强制程序员处理异常。

比如这段代码sn -p -

try
{
}
catch(IOException e)
{
}

无效

但是为什么编译器不以相同的方式处理抛出从未在方法体中抛出的检查异常的方法?

比如这段代码sn -p -

void test() throws IOException
{
}

令人惊讶地有效

请解释其背后的原因。 TIA。

【问题讨论】:

  • 这能回答你的问题吗? stackoverflow.com/questions/35184092/…
  • 不完全是。它更强调捕获检查的异常。我的问题是关于声明从未抛出的已检查异常。
  • 必须允许方法声明它们抛出异常,即使它们实际上并没有抛出它,因为覆盖方法(可能)声明它们抛出基类方法抛出的检查异常。并且这些方法的覆盖可能需要抛出异常。

标签: java exception ioexception checked throws


【解决方案1】:

因为您可能希望允许子类抛出此异常。

public abstract class Parent {
  public void doStuff() {}
}
public class Child {
  // this is illegal, because you throw more exceptions than the overridden method
  public void doStuff() throws IOException {}
}

这对于接口来说更加直观,其(非default)方法永远不会抛出异常但可以声明它。

【讨论】:

    【解决方案2】:

    It is a compile-time error如果一个catch子句可以catch检查 异常类 E1 并且 try 块不是这种情况 对应catch子句可以抛出检查异常类 是 E1 的子类或超类,除非 E1 是 Exception 或 异常的超类。

    这告诉你所有这些都是有效的:

    try { }
    catch(Exception e){}
    

    --

    try{ }
    catch(NullPointerException  e) {}
    

    --

    try{ }
    catch(ArrayIndexOutOfBoundsException  e) {}
    

    --

    try{ }
    catch(RuntimeException e) {}
    

    --

    try{ }
    catch(Error e) {}
    

    --

    try{ }
    catch(Throwable e){ }
    

    它与 void 块无关。它与您检查的异常子类的不可能路径有关。


    Exception 的子类会发生什么情况?例如 IOexception:那些是无法到达的 catch 块。 try 块中的任何内容都不会导致该异常,因此编译器只会告诉您:该块永远不会被执行,因为它永远不会捕获该 subException。

    throws的区别:在这个上下文中不存在无法访问代码的概念。方法抛出异常的可能性并不以方法的定义结束。例如:

    abstract void readFile(String path) throws IOException;
    

    这个方法甚至没有块,因为它是一个抽象方法。很容易猜到这条线永远不会抛出任何 IOException。但它为将实现它的扩展定义了一种行为。为了覆盖它,你的方法必须抛出IOException

    同样,如果有人重写了你的测试方法:

    @Override
    void test() throws IOException
    {
       readFile(file);
    }
    

    与您的第一个 try-catch 块相反,这并非不可能发生。

    【讨论】:

      【解决方案3】:

      Java 遵循“处理或声明”的规则。

      如果您的代码中声明了已检查异常,您必须处理它(在 try/catch 块中)或声明它(在方法签名上添加“抛出”)。

      当您说您的方法可能会引发异常时,使用您的方法的每个人都必须处理或声明该异常。如果您处理它,您就可以使您的代码能够恢复。如果您声明它,您就是将问题传递给调用者。

      如果你声明'throws',编译器就很好,他知道当你的方法被调用时要做什么。

      如果您声明一个实际上并不存在的异常,您就是在让您的代码的用户意识到,在未来的版本中,您可能会添加该异常。用户将为您添加该例外的那一天做好准备。

      【讨论】:

        【解决方案4】:

        Specifying 表示方法可以抛出异常,也可以不抛出。但编译器不检查它,因为他不能,实际上。所以尝试块只检查指定。这 关键是编译器看不到实际调用异常和方法指定之间的区别。如果您在 try 块中调用 test(),它将有效。对不起我的英语)

        【讨论】:

          猜你喜欢
          • 2021-04-20
          • 1970-01-01
          • 1970-01-01
          • 2014-10-09
          • 2014-01-19
          • 1970-01-01
          • 1970-01-01
          • 2016-05-07
          • 1970-01-01
          相关资源
          最近更新 更多