1 前言
在我们的开发过程中,我们会遇到很多的异常。虽然我们碰到了这些异常,但都是很敷衍的进行了一些处理。而没有从根本上来进行理解。今天,我系统的重新学习一下。
2 异常的经典面试题
首先是一个异常的经典面试题,求返回值,正确大碍不是4,而是0!
1 public static void main(String[] args) {
2 System.out.println(getReturn(2));
3 }
4
5 private static int getReturn(int i) {
6 try {
7 int r = i * i;
8 return r ;
9 } finally {
10 if (i == 2) {
11 return 0;
12 }
13 }
14 }
正常情况下,finally为最后执行的。即使前面已经有返回值了,但是当执行到finally又产生了新的返回值就会把原有值给覆盖。
3 异常的分类
所有的异常都是派生于Throwalbe的一个实例。Throwable类有两个子类:Error 和Exception。针对Error为Java的运行环境所导致的错误或者资源耗尽的错误。应用程序不应该会抛出该异常。如果真是出现了这种异常,除了通知用户,并尽力停止程序外,也没有什么别的其他的方式了;在进行Java程序开发时,需要特别注意Exception这个异常。这个异常又有两个子类,他们分别为:RuntimeException和其他。RuntimeException表示程序错误导致的异常,但是如果本来程序能够正常运行,但是由于某些情况(如I/O操作)引起的程序错误就不属于运行时异常了,而是属于其他类别里面了。
4 异常执行顺序
1 public static void main(String[] args) {
2 try {
3 //code 1
4 throw new IOException();
5 //code 2
6 } catch (IOException e) {
7 //code 3
8 e.printStackTrace();
9 //cdoe 4
10 } finally {
11 // code 5
12 }
13 //code 6
14 }
4.1 代码中没有异常抛出
执行try块中的所有代码,然后执行finally块中的代码。执行顺序:1 2 5 6;
4.2 代码中抛出的异常能被catch块捕获
执行try块中之前的代码,抛出异常后执行catch块中代码,最后执行finally块中的代码。 执行顺序: 1 3 4 5 6;
4.3 如果在catch中又抛出异常
执行try块中之前的代码,抛出异常后执行catch块中抛出异常前的代码,最后执行finally块中的代码。 执行顺序: 1 3 5 6;
4.4 如果没有catch捕获该异常
执行try块中的代码,然后执行finally块中的代码。 执行顺序: 1 5 6;
5 使用异常机制的一些建议
5.1 异常处理不能代替简单的测试
尽量对所有情况进行检查,而不是用异常机制来对错误进行处理。因为是哦那个try/catch速度会下降很多。
5.2 不要过多的细化异常
尽量把能产生异常的代码包在同一个try/catch块中去。这样可以让整个逻辑代码更加通畅,不被try/catch块打乱。
5.3 合理利用异常的层次结构
不要只抛出RuntimeException,应该寻找更加合适的异常子类或者自己建立异常类。
5.4 不要压制异常
代码中万万不能出现,catch中捕获了异常而不做任何处理的情况出现。这样会压制下异常,让异常逃脱编译器的检查。隐藏了异常,给整个程序留下了较大的隐患。
5.5 在检查错误时,"苛刻"要比放任更好
在有错误发生时,尽量还是抛出一个异常比直接抛出一个null或者自定义的数字类型要好。这样可以放大异常,提高对错误的检查强度。
5.6 不要羞于传递异常
在异常中,可以尽量对异常进行抛出,而不是非要进行处理的。
5.7 异常的一个处理原则就是"早抛出,晚捕获"
有错误发生了,就及早抛出一个异常。中间层可以考虑进行抛出异常,让较高层来捕获异常,针对异常来进行相应处理。