是否可以使用已检查的异常来抛出未经检查的异常?

时间:2017-12-28 20:34:42

标签: java exception-handling

我正在运行以下代码:

import java.io.FileNotFoundException;
import java.io.IOException;

class Basic1 {
    int c;

    void calculation(int a, int b) throws Exception {
        c = a / b;
    }
}

class Basic extends Basic1 {
    void calculation(int a, int b) throws IOException {
        c = a / b;
        RuntimeException ae = new ArithmeticException();
        throw ae;
    }

    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        int c;
        Basic ba = new Basic();
        try {
            ba.calculation(a, b);
        } catch (IOException e) {
            System.out.println("Zero can't be there in the denominator. : IoException");
        } catch (ArithmeticException e) {
            System.out.println("Zero can't be there in the denominator. : Arthimetic Exception");
        } catch (Exception e) {
            System.out.println("Zero can't be there in the denominator. : Exception");
        }
    }
}

该程序正在成功编译并输出“Zero in the den in the denominator。:Arthimetic Exception”(输出符合预期)。

我的问题是该程序如何成功编译?为什么我在内部IOException时抛出calculation()时没有收到错误我正在创建一个RuntimeException对象?

我的第二个问题是程序进入catch (ArithmeticException e)子句,编译器是否在运行时决定catch将执行?我理解正确吗?

1 个答案:

答案 0 :(得分:0)

对于您的第一个问题,使用throws E(其中E是一些任意检查的异常)构造的方法不必抛出任何东西。这意味着任何调用你的方法的人都必须能够处理E,这允许你的方法抛出E而不处理它。否则这将是编译错误。通常,方法的文档指定何时抛出E。用JLS的话说:

  

本质上,对于可能由于执行方法或构造函数的主体而导致的每个已检查异常,除非在声明的throws子句中提及其异常类型或其异常类型的超类型,否则会发生编译时错误。方法或构造函数。

这并不是说您必须在方法体内抛出给定的已检查异常。请注意,您可以将throws与未经检查的异常一起使用,但这对程序没有影响,因为未经检查的异常可能会在未经处理的情况下被抛出。这就是他们的观点。

在您的代码中,您抛出RuntimeException。根据定义,任何扩展RuntimeException(包括其自身)的类都不会被检查。 ArithmeticException就是其中之一,因此您可以将其分配给RuntimeException类型的变量,然后在throws子句中指定它而不抛出它。

对于第二个问题,我假设编译器没有优化各种catch子句。在这种情况下,不,在编译时不确定执行的catch。当程序中抛出任何异常时,它会向上传播,直到被捕获为止。如果不是,则暂停执行,并将堆栈跟踪打印到System.err。由于抛出ArithmeticException,第一个catch子句不匹配但第二个子句不匹配,因此执行。第三个(catch (Exception e))匹配,但是使用catch子句进行排序并且只执行一个,因此这里不执行该子句。

但是,在这种情况下,编译器优化掉catch子句并将程序直接指向catch (ArithmeticException e)子句中的代码并不是不可思议的,因为您的方法将始终抛出{{ 1}}。但是,必须考虑的是,任何代码行都可能会抛出一些模糊的错误,如ArithmeticException;在优化时,编译器必须允许这样的边缘情况。