Java重写throws子句

时间:2015-09-05 10:50:34

标签: java methods signature override throws

我正在通过阅读S G Ganesh和Tushar Sharma撰写的书来学习OCJP考试。在页346,有一个文字说:

  

如果您尝试更改throws子句怎么办?在重写方法中有许多方法可以更改throws子句,包括以下内容:
  一个。不提供任何抛出条款。
  湾列出更多常规检查的异常以进行抛出   C。除了基本方法中给定的已检查异常外,还列出了更多已检查的异常   如果您尝试这三种情况中的任何一种,您将收到编译器错误。例如,尽量不要在实现IntReader接口的类中的readIntFromFile()方法中提供throws子句。

public int readIntFromFile() {
    Scanner consoleScanner = new Scanner(new File("integer.txt"));
    return consoleScanner.nextInt();
}
     

您将收到此编译器错误:“未报告的异常FileNotFoundException;必须被抓或宣布被抛出。“
  总而言之,基类方法的throws子句是​​它为该方法的调用者提供的契约:
  它表示调用者应该处理列出的异常或在其throws子句中声明这些异常。覆盖基本方法时,派生方法也应遵守该合同。基本方法的调用者   准备只处理基本方法中列出的异常,因此覆盖方法不能抛出更一般的或除了列出的已检查异常之外。
  但是,请注意,派生类方法的throws子句应遵循基本方法的throws子句的约定的讨论仅限于已检查的异常。与基类方法的throws子句相比,仍可以在合同中添加或删除未经检查的异常。例如,请考虑以下事项:

public int readIntFromFile() throws IOException, NoSuchElementException {
    Scanner consoleScanner = new Scanner(new File("integer.txt"));
    return consoleScanner.nextInt();
}
     

这是一个可接受的throws子句,因为可以从readIntFromFile()方法抛出NoSuchElementException。此异常是未经检查的异常,当nextInt()方法无法从文件中读取整数时,它会被抛出。这是一种常见情况,例如,如果您有一个名为integer.txt的空文件;尝试从此文件中读取整数将导致此异常。

我有点担心“a。”这一点。它说如果你不提供任何throws子句,代码将无法编译。但是当我学习OCA时,我记得我读过你可以提供相同的throws子句,一个更具体的Exception或者没有throws子句,代码仍然会编译,这些只适用于Checked Exceptions。 我试过做一些测试,但我不能得到“未报告的异常FileNotFoundException;必须被抓住或 宣布被抛出。“我记得我看过了,但我不知道在哪种情况下。

5 个答案:

答案 0 :(得分:2)

好吧,这本书错了:

class A {
    public void foo() throws FileNotFoundException {

    }
}

class B extends A {
    public void foo() {

    }
}

编译好。对于这样的语言特性,最好参考Java语言规范。

答案 1 :(得分:2)

正如马努蒂所说,这本书是错误的。你肯定可以有更精确或没有例外,但你不能有更普遍的:

Array.prototype.indexOf()

答案 2 :(得分:1)

反例A

这一本书在A点上是错误的。

以下代码编译完全正确:

class A {
    void method() throws GeneralSecurityException {
    }
}

class B extends A {
    void method() {
    }
}

班级B显然使A点无效。

反例C

这本书也过于简化了C点:只要抛出的异常是已经抛出的已检查异常的子类,代码就是正确的。

class C extends A {
    void method() throws NoSuchAlgorithmException, InvalidKeyException {
    }
}

代码NoSuchAlgorithmExceptionInvalidKeyExceptionGeneralSecurityException的子类。

C显示了C点的过度简化。

JLS参考

以下是The Java Language Specification, Java SE 8 Edition, chapter 11.2中的状态:

  

...

     

throws子句中命名的已检查异常类(第11.1.1节)是方法或构造函数的实现者和用户之间的契约的一部分。重写方法的throws子句可能没有指定此方法将导致抛出任何被抛出的方法不允许被抛出的方法抛出的任何已检查异常(§8.4.8.3)。

     

...

8.4.8.3中的引用内容为:

  

...

     
      
  • 如果m2有一个throws子句提到任何已检查的异常类型,则m1必须有throws子句,否则会发生编译时错误。
  •   
  • 对于throws的{​​{1}}子句中列出的每个已检查异常类型,m2子句的擦除(第4.6节)中必须出现相同的异常类或其超类型之一throws;否则,发生编译时错误。
  •   
     

...

讨论JLS文本

这些JLS章节是有道理的。最后,调用声明特定已检查异常的方法的代码将具有处理该特定已检查异常的代码。如果子类实例的方法抛出另一个已检查的异常,则不太可能处理已检查的异常。另一方面,如果方法没有抛出调用者期望的任何异常,则调用者可以。将不会调用异常处理代码。

代码应始终期望接收运行时异常,因此基于m1的异常免于编译时检查。

经验法则

只要您只抛出调用者期望的异常,代码就可以了。

答案 3 :(得分:0)

这本书混合了两件事。它讨论的是子类中的重写throws子句,但它提供的示例与此完全无关:

public int readIntFromFile() {
    Scanner consoleScanner = new Scanner(new File("integer.txt"));
    return consoleScanner.nextInt();
} 

您将在此处收到编译错误,因为Scanner构造函数会抛出FileNotFoundException,但readIntFromFile()中未捕获或传播该readIntFromFile()。也就是说,class A { void meth() throws IOException { // ... } } class B extends A { @Override public void meth() { super.meth(); // compile error here // ... } } 的声明并不清楚它可能会引发异常。

仅当子类中的方法调用其超级方法时,这适用于子类/基类:

src/post/2015-01-01-filename.md

答案 4 :(得分:0)

java中的

java.io.Printwritter/PrintStream :: close() api是超类(IOException抛出的java.io.OutputStream :: close()的最好例子,在子类中被忽略了。

还有一件事是

try {
   //CheckedExceptionX must be thrown from here
}
catch(CheckedExceptionX e) {
}

然而

public void someAPI throws CheckedExceptionX {
     //trowing CheckedExceptionX is not mandatory in this method
     //Means this body can be free from throwing that mentioned CheckedException 
}