一、常见异常类型
-
Error
实现了Throwable接口,Error是JVM层的错误,是程序中无法处理的错误,表示运行应用程序中出现了严重的错误。
-
Exception
实现了Throwable接口,Exception是代码逻辑错误,程序本身可以捕获并且可以处理的异常。
- 一类是 IOException(I/O 输入输出异常),其中 IOException 及其子类异常又被称作「受查异常」
- 另一类是 RuntimeException(运行时异常),RuntimeException 被称作「非受查异常」。
受查异常就是指,编译器在编译期间要求必须得到处理的那些异常,你必须在编译期处理了。
-
自定义异常类型
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
二、异常处理
-
try…catch关键字
try { // 程序代码 } catch(ExceptionName e1) { //Catch 块 }
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。
try{ // 程序代码 }catch(异常类型1 异常的变量名1){ // 程序代码 }catch(异常类型2 异常的变量名2){ // 程序代码 }catch(异常类型2 异常的变量名2){ // 程序代码 }
-
throws/throw 关键字
如果一个方法没有捕获一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
public class className { public void deposit(double amount) throws RemoteException { // Method implementation throw new RemoteException(); } //Remainder of class definition }
-
finally关键字
finally 关键字用来创建在 try 代码块后面执行的代码块。
无论是否发生异常,finally 代码块中的代码总会被执行。在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
try{ // 程序代码 }catch(异常类型1 异常的变量名1){ // 程序代码 }catch(异常类型2 异常的变量名2){ // 程序代码 }finally{ // 程序代码 }
-
try-catch-finally 的执行顺序
- 情况1:try{} catch(){}finally{} return;
显然程序按顺序执行。 - 情况2:try{ return; }catch(){} finally{} return;
程序执行try块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,最后执行try中return;
finally块之后的语句return,因为程序在try中已经return所以不再执行。 - 情况3:try{ } catch(){return;} finally{} return;
程序先执行try,如果遇到异常执行catch块,- 有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码,
最后执行catch块中return. finally之后也就是4处的代码不再执行。 - 无异常:执行完try再finally再return.
- 有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码,
- 情况4:try{ return; }catch(){} finally{return;}
程序执行try块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,因为finally块中有return所以提前退出。 - 情况5:try{} catch(){return;}finally{return;}
程序执行catch块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,因为finally块中有return所以提前退出。 - 情况6:try{ return;}catch(){return;} finally{return;}
程序执行try块中return之前(包括return语句中的表达式运算)代码;- 有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;
则再执行finally块,因为finally块中有return所以提前退出。 - 无异常:则再执行finally块,因为finally块中有return所以提前退出。
- 有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;
最终结论:
- 任何执行try或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的, 编译器把finally中的return实现为一个warning。
- 如果try中有return或者catch中有return,但是finally中没有return的情况下,会先执行finally再返回最后一步执行到的return前,执行return。
- 情况1:try{} catch(){}finally{} return;
例: finally 语句块在 catch语句块中的return语句之前执行? 错误,是在return完成之前,而非return之前
三、常见面试题
以下面试题是在个人就业过程中遇到的一些常问的题目,后续找到有价值或者面试官比较关心的再补充。
-
说一说运行时异常(RunTimeException):
运行时异常可以不进行处理,这样的异常由虚拟机接管。出现运行时异常后,系统会把异常一直往上层抛,一直直到遇到处理代码。如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。
常见的运行时异常有:
- NullPointerException (空指针异常):调用了未经初始化的对象或者是不存在的对象,这个错误经常出现在创建图片,调用数组这些操作中。规避:进行if判断,是否为null。
- ClassNotFoundException (找不到类异常):“指定的类不存在”,这里主要考虑一下类的名称和路径是否正确即可 。
- ArrayIndexOutOfBoundsException (下标越界异常):“数组下标越界”,现在程序中大多都有对数组的操作,因此在调用数组的时候一定要认真检查,看自己调用的下标是不是超出了数组的范围,一般来说,显示(即直接用常数当下标)调用不太容易出这样的错,但隐式(即用变量表示下标)调用就经常出错了。可以使用数组length属性,避免越界。
- IndexOutOfBoundsException (索引越界异常):索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。
- NoSuchMethodError(方法不存在异常) :方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。
- ClassCastException( 类型强制转换异常 ) - 类型强制转换异常 。
-
Exception和Error的区别?
- Error是JVM层的错误,是程序中无法处理的错误,表示运行应用程序中出现了严重的错误。
- Exception是代码逻辑错误,程序本身可以捕获并且可以处理的异常。
-
try-catch-finally 的执行顺序?
见上文
-
final、finally、finalize的区别?
- final:常用在逻辑代码中,final关键字可以用来修饰类、方法和变量。当用final修饰一个类时,表明这个类不能被继承;当用final修饰一个方法时,父类的final方法是不能被子类所覆盖的;final修饰的成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- finally:在异常处理时提供finally块来执行清楚操作。如果抛出一个异常,那么相匹配的catch语句就会执行,然后控制就会进入finally块,如果有的话。
- finalize:方法名。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除之前做必要的清理工作。这个方法是在垃圾收集器在确定了,被清理对象没有被引用的情况下调用的。