Java异常常见面试题整理

1. Error和Exception有什么区别

Throwable存在两个子类:

1.Error:表示的是系统级的错误,是JVM发出的错误操作,不能指望程序处理这个问题,无法用代码处理,只能尽量避免。

2.Exception:一般表示所有程序中的错误,是由程序设计不完善出现的问题,所以一般在程序中将进行try…catch的处理。

2. RuntimeExcepion与Exception的区别

注意观察如下方法的源码: Integer类: public static int parseInt(String text)throws NumberFormatException

此方法抛出了异常, 但是使用时却不需要进行try-catch捕获处理,原因: 因为NumberFormatException并不是Exception的直接子类,而是RuntimeException的子类,只要是 RuntimeException的子类,则表示程序在操作的时候可以不必使用try…catch进行处理,如果有异常发生,则由JVM进行处理。当然,也可以通过try-catch处理。

3. Java中异常处理机制的原理

Java中异常处理是通过5个关键词来实现的:try, catch, throw, throws, finally

一般情况下是用try来执行一段程序,如果出现异常,则系统会抛出(throws),可以通过具体的类型来捕捉它,或最后由缺省处理器来处理它(finally)。

try:执行可能异常的程序

catch:跟在try后面,用来捕获异常

throw:用来明确的抛出一个异常

throws:用来标明可能抛出的各种异常

finally:确保一段代码无论发生什么异常都会被执行的一段代码,除非程序结束或软件在内存消失

4. try-catch-finally 中哪个部分可以省略

catch和finally可以省略其中一个 , catch和finally不能同时省略 注意:格式上允许省略catch块, 但是发生异常时就不会捕获异常了,我们在开发中也不会这样去写代码。

5. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗

执行流程:

1. 先计算返回值, 并将返回值存储起来, 等待返回

2. 执行finally代码块

3. 将之前存储的返回值, 返回出去;

需注意:

1. 返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值做任何的改变,返回的值都不会改变

2. finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值不是try或catch中的值

3. 如果在try或catch中停止了JVM,则finally不会执行。例如停电-, 或通过如下代码退出 JVM:System.exit(0);

Example:

1. 第一个例子代码如下,尽管try设置p的年龄为18然后return,但是还是执行finally的重新设置年龄为28,最后结果为28。 

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        System.out.println(getAge(p).getAge());
    }

    private static Person getAge(Person p){
        try{
            p.setAge(18);
            return p;
        }catch(Exception e){
            return null;
        }finally {
            p.setAge(28);
        }
    }
}

 2. 这里跟例子1相似的情况,但是最后返回却是2,相比例子1中new Person()是在堆中有相应的内存地址,所以finally执行的时候已经修改具体内容,而这里try a=2, return a,a是先备份了作为常亮2返回给main函数,后续的a的改动不影响返回值。

public class Main {
    public static void main(String[] args) {
        int i = getInt();
        System.out.println(i);
    }

    private static int getInt() {
        int a = 1;
        try {
            a = 2;
            return a;
        } catch (Exception e) {
            a = 3;
        }finally{
            a = 4;
        }
        return a;
    }
}

6. final、finally、finalize 有什么区别

  • final:是修饰符,如果修饰类,此类不能被继承;如果修饰方法和变量,则表示此方法和此变量不能在被改变,只能使用。
  • finally:是 try{} catch{} finally{} 最后一部分,表示不论发生任何情况都会执行,finally 部分可以省略,但如果 finally 部分存在,则一定会执行 finally 里面的代码。
  • finalize:属于Object类的一个方法,而Object类是所有类的父类,Java 中允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

 7. 常见的异常类有哪些?

  • NullPointerException:空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性。
  • ArithmeticException:算术条件异常。譬如:整数除零等。
  • NumberFormatException:数字格式异常。当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
  • ArrayIndexOutOfBoundsException:数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
  • IndexOutOfBoundsException:索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。

阿里巴巴 Java 开发手册之异常处理

1. 【强制】Java 类库中定义的一类RuntimeException可以通过预先检查进行规避,而不应该通过catch 来处理,比如:IndexOutOfBoundsException,NullPointerException等等。

说明:无法通过预检查的异常除外,如在解析一个外部传来的字符串形式数字时,通过catch NumberFormatException来实现。 正例:if (obj != null) {...} 反例:try { obj.method() } catch (NullPointerException e) {...}

2. 【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。

3. 【强制】对大段代码进行try-catch,这是不负责任的表现。catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理。

4. 【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。

5. 【强制】有try块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意手动回滚事务。

6. 【强制】finally块必须对资源对象、流对象进行关闭,有异常也要做try-catch。 说明:如果JDK7及以上,可以使用try-with-resources方式。

7. 【强制】不能在finally块中使用return,finally块中的return返回后方法结束执行,不会再执行try块中的return语句。(常识)

8. 【强制】捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。 说明:如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况。

9. 【推荐】方法的返回值可以为null,不强制返回空集合,或者空对象等,必须添加注释充分说明什么情况下会返回null值。调用方需要进行null判断防止NPE问题。

说明:本规约明确防止NPE是调用者的责任。即使被调用方法返回空集合或者空对象,对调用者来说,也并非高枕无忧,必须考虑到远程调用失败,运行时异常等场景返回null的情况。

10. 【推荐】防止NPE,是程序员的基本修养,注意NPE产生的场景:

 1) 返回类型为包装数据类型,有可能是null,返回int值时注意判空。     反例:public int f() { return Integer对象}; 如果为null,自动解箱抛NPE。
 2) 数据库的查询结果可能为null3) 集合里的元素即使isNotEmpty,取出的数据元素也可能为null4) 远程调用返回对象,一律要求进行NPE判断。
 5) 对于Session中获取的数据,建议NPE检查,避免空指针。
 6) 级联调用obj.getA().getB().getC();一连串调用,易产生NPE。

正例:可以使用JDK8的Optional类来防止NPE问题。

11. 【推荐】在代码中使用“抛异常”还是“返回错误码”,对于公司外的http/api开放接口必须使用“错误码”;而应用内部推荐异常抛出;跨应用间RPC调用优先考虑使用Result方式,封装isSuccess、“错误码”、“错误简短信息”。

说明:关于RPC方法返回方式使用Result方式的理由:
1)使用抛异常返回方式,调用方如果没有捕获到就会产生运行时错误。
2)如果不加栈信息,只是new自定义异常,加入自己的理解的error message,对于调用端解决问题的帮助不会太多。如果加了栈信息,在频繁调用出错的情况下,数据序列化和传输的性能损耗也是问题。

12. 【推荐】定义时区分unchecked / checked 异常,避免直接使用RuntimeException抛出,更不允许抛出Exception或者Throwable,应使用有业务含义的自定义异常。推荐业界已定义过的自定义异常,如:DAOException / ServiceException等。

13. 【参考】避免出现重复的代码(Don’t Repeat Yourself),即DRY原则。 说明:随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是共用模块。

正例:一个类中有多个public方法,都需要进行数行相同的参数校验操作,这个时候请抽取:private boolean checkParam(DTO dto) {...}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值