Java错误与异常
1.错误与异常 基本介绍
Java分为Error和Exception,它们之间的区别
Error:程序发生错误,脱离程序员的控制,比如内存超出,非程序员编写的程序出现问题等,由Java虚拟机抛出错误
Exception:则分为受检异常 和 非受检异常
1.受检异常 直接继承于Exception,编写时不进行异常处理,则会出现错误
常见的比如IO异常,通常直接抛出异常等等
2.非受检异常(也称运行时异常) 直接继承于RuntimeException,编写时不报错误,通常参数出现问题时JVM抛出错误
常见的异常包括空指针,算数异常(除数为0)等等
2.异常发生处理
处理方式有两种:
(1)throws抛出
throws关键字,此关键字主要在方法的声明上使用,表示方法中不处理异常,而交给调用处处理。
格式:
返回值 方法名称()throws Exception{
}
(2)try···catch···finally捕获异常处理
try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){
// 异常的处理操作
} ...
finally{
// 异常的统一出口
}
try+catch的处理流程
1、 一旦产生异常,则系统会自动产生一个异常类的实例化对象。
2、 那么,此时如果异常发生在try语句,则会自动找到匹配的catch语句执行,如果没有在try语句中,则会将异常抛出.
3、 所有的catch根据方法的参数匹配异常类的实例化对象,如果匹配成功,则表示由此catch进行处理。
finally
在进行异常的处理之后,在异常的处理格式中还有一个finally语句,那么此语句将作为异常的统一出口,不管是否产生
了异常,最终都要执行此段代码。
(3) 人为抛出异常
throw关键字表示在程序中明确地抛出一个异常,因为从异常处理机制来看,所有的异常一旦产生之后,实际上抛出
的就是一个异常类的实例化对象,那么此对象也可以由throw直接抛出。
代码: throw new Exception("自定义异常。") ;
3.常见的关于异常处理的面试题
1.上文说到的finally在不管有异常还是没有异常发生的情况下,最终都需要执行finally,那么什么情况下不执行finally?
两种情况:
非正常情况下:如断电,关闭程序等等,导致内存被清理,finally不执行
正常情况下:
try{
异常;
}catch(){
System.exit(0);//人为因素,直接退出程序,finally不执行,参数0是正常退出,非0为非正常退出
}finally{
}
2.try-catch-finally 中哪个部分可以省略?
catch和finally可以省略其中一个 , catch和finally不能同时省略
注意:格式上允许省略catch块, 但是发生异常时就不会捕获异常了,我们在开发中也不会这样去写代码.
3.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?什么时候被执行,在return前还是后?
finally中的代码会执行,在方法返回调用者前执行。
详解:
执行流程:
1. 先计算返回值, 并将返回值存储起来, 等待返回
2. 执行finally代码块
3. 将之前存储的返回值, 返回出去;
语言描述:try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,
然后如果在finally中修改了返回值,就会返回修改后的值。
需注意:
1. 返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值做任何的改变,返回的值都不会改变
2. finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值不是try或catch中的值
4.对上面第3点的补充,finally返回具体的值还得看参数值的数据类型,如
try{
int a = 10;
}catch{
return null;
}finally{
a = 20;
retturn a;
}
答案:返回a的值为10
基本数据类型finally下仅仅把参数值进行复制,仍然返回的是原来的值
try{
Person p = new Person();
p.setAge(10);
}catch{
p.setAge(20);
}finally{
p.setAge(30);
}
System.ou.print(p.setAge(10));
答案:输出的是30
引用数据类型finally下保存的是引用的地址,栈中原地址对应堆中的值改变,再输出值也相应发生改变
5.列出你常见的运行时异常
- ArithmeticException(算术异常)
- ClassCastException (类转换异常)
- IllegalArgumentException (非法参数异常)
- IndexOutOfBoundsException (下标越界异常)
- NullPointerException (空指针异常)
- SecurityException (安全异常)
6.类ExampleA继承Exception,类ExampleB继承ExampleA。执行此段代码的输出是什么?
有如下代码片断:
try {
throw new ExampleB("b")
} catch(ExampleA e){
System.out.println("ExampleA");
} catch(Exception e){
System.out.println("Exception");
}
答:输出:ExampleA。(根据里氏代换原则[能使用父类型的地方一定能使用子类型],抓取ExampleA类型异常的catch块能够抓住
try块中抛出的ExampleB类型的异常)
7.说出下面代码的运行结果。(此题的出处是《Java编程思想》一书)
class Annoyance extends Exception {}
class Sneeze extends Annoyance {}
class Human {
public static void main(String[] args) throws Exception {
try {
try {
throw new Sneeze();
}
catch ( Annoyance a ) {
System.out.println("Caught Annoyance");
throw a;
}
}
catch ( Sneeze s ) {
System.out.println("Caught Sneeze");
return ;
}
finally {
System.out.println("Hello World!");
}
}
}
答案是:
Caught Annoyance
Caught Sneeze
Hello World!