我正在运行以下代码:
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
将执行?我理解正确吗?
答案 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
;在优化时,编译器必须允许这样的边缘情况。