1、说一说你对异常的理解?
异常是程序在执行过程中可能发生的一些错误,它会暂时终止程序,并转到异常处理部分尝试恢复。异常的出现可以使我们把程序中可能出现错误的代码从正常代码中分离出来,单独进行处理。
2、异常有哪些种类,可以举几个例子吗?(指导:先回答分类,之后举几个自己经常看到的例子)
类似于 Object 类,Throwable 是所有异常的父类。下一层分为 Error 类和 Exception 类。
Error 类表示严重的错误,一般由 JVM 和底层系统引发,并且不可恢复,例如内存溢出,class 没有主方法等。Exception 类是可以被程序捕获和处理的异常情况。
Exception 再往下,按照异常的性质又分为编译异常 CheckedException 和运行时异常 RuntimeException。其中检查异常在编译阶段就能被检测出,例如 IO 异常 IOException,文件找不到异常 FileNotFoundException等。运行时异常只有在程序运行时才能被检测出,例如空指针异常 NullPointerException,数组下标越界 ArrayIndexOutOfBoundsException 等。
3、throw 和 throws 有啥区别?直接 try catch 不好吗,为啥还要抛呢?(指导:有时候自己无法处理,必须得让调用该方法的人来处理,于是得用抛出)
throw 用在方法体内,表示某个地方需要抛出一个异常,是一个具体的动作。而 throws 用在方法声明后面,表示这个方法可能会抛出哪些异常,是一个声明。
这个需要分情况对待。首先,对于能在方法内处理的异常,可以直接用 try catch,但对于在当前方法内无法处理的异常,我们只能选择抛出,将它交给方法调用者去处理。其次,有时多个方法可能会抛出相同类型的异常,如果每个方法都用 try catch 会非常冗余,这时可以在这些方法中只 throw,在调用这些方法的地方整体 try catch,统一进行处理。
还有的话就是,有时候得把异常交给上层调用的人来处理。
4、try catch会影响性能吗?为什么抛出异常的时候会影响性能?
几乎不会,也就是程序没有异常时,try catch 加和不加性能几乎一样,只有在程序有异常需要捕获时才会影响性能。
原因在于,处理异常的 catch 语句在 class 文件中是用异常表实现的。异常表有四个字段,分别是 From, To, Target 和 Type。From 和 To 分别对应 try 块对应的行号,如果其中有异常抛出,会跳转到 Target 对应的行号,也就是 catch 语句对应的位置,而这个异常的类型记录在 Type 中。如果程序在 try 中没有异常抛出,最终会通过一条 goto 指令跳转到 try catch 块后的语句继续执行,这一条 goto 指令性能的消耗可以忽略不计。如果有异常,才会去查异常表,再跳转到对应的 catch 块位置去执行,这个过程可能会影响性能。
5、try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?(指导:finally是异常的地方,可以说一说
会的,无论 catch 块中有异常还是有返回语句,最终一定会在方法真正结束之前执行 finally。但是需要考虑一种特殊情况,就是如果 try 块中抛出了异常但没有被 catch 捕获,且此时 finally 中也抛出了异常,那么 finally 中的异常会覆盖掉 try 中的异常,成为这个方法最终抛出的异常。实践中需要注意一下这个异常覆盖问题。