问题及答案来源自《Java程序员面试笔试宝典》第四章 Java基础知识 4.6异常处理
1、finally的代码什么时候被执行?
问题描述:
try{}里有一个return语句,那么紧跟在这个try后的finally{}中的代码是否会执行?如果会的话,什么
时候被执行?是在return之前还是之后?
解释如下:
在Java的异常处理中,finally的作用是保证无论什么情况finally中的代码最后一定会执行,由于程序
执行return意味着结束对当前函数的调用并跳出代码体,因此任何语句要执行都只能在return前执行,
因此finally块里的代码是在return前执行
另外,如果finally中有return语句,那么finally中的return语句会覆盖别处的return语句,最终回到调用
者那里的是finally块中的return值,示例如下:
1 public class FindLeftAndRightBigger { 2 3 public static int testFinally(){ 4 try{ 5 return 1; 6 } catch(Exception e){ 7 return 0; 8 } finally{ 9 System.out.println("in finally"); 10 } 11 } 12 13 public static int testFinally2(){ 14 try{ 15 return 1; 16 } catch(Exception e){ 17 return 0; 18 } finally{ 19 System.out.println("in finally"); 20 return 3; 21 } 22 } 23 24 public static void main(String[] args) { 25 System.out.println(testFinally()); // 1 26 System.out.println(testFinally2()); // 3 27 } 28 }
最后输出结果:
in finally
1
in finally
3
return:
return在返回的时候不是直接返回变量而是复制一份然后返回,对于基本数据类型,在finally块中
改变要return的值对返回值没有影响,但对引用类型的数据会有影响,实例如下:
1 public class finallyDemo{ 2 public static int testFinally(){ 3 int res = 1; 4 try{ 5 res = 2; 6 return res; 7 } catch(Exception e){ 8 return 0; 9 } finally{ 10 res = 3; 11 } 12 } 13 14 public static StringBuffer testFinally2(){ 15 StringBuffer s = new StringBuffer("Hello"); 16 try{ 17 return s; 18 } catch(Exception e){ 19 return null; 20 } finally{ 21 s.append("666"); 22 } 23 } 24 25 public static void main(String[] args) { 26 System.out.println(testFinally()); 27 System.out.println(testFinally2()); 28 } 29 }
输出结果:
2
Hello666
引申 - 出现在Java程序中的finally中的finally代码块是否一定会被执行?
答案:不一定会被执行,下面是两个实例
- 情况1:当程序在进入try语句之前就出现异常时,会直接结束,不会执行finally块中的代码
- 情况2:当程序在try块中强制退出时也不会执行finally块中的代码(exit)
2、异常处理的原理是什么?
异常:是指程序运行时(非编译时)所发生的非正常情况或错误,当程序违反了语义规则时,JVM就会将出现的
错误表示为一个异常并抛出
异常可以在catch程序块中捕获,然后进行处理,异常处理的目的就是为了提高程序的安全性和鲁棒性
Java语言如何处理异常:
Java把异常当作对象来处理,定义了一个基类(java.lang.Throwable)作为所有异常的父类
在JavaAPI中已经定义了许多异常类,这些异常类分为Error(错误)和Exception(异常)两大类
违反语义规则:
- Java内置语义检查,eg数组下标越界引发IndexOutOfBoundsException,访问空对象引发NullPointerException
- 开发人员拓展的语义检查,开发人员可以创建自己的异常类,并自由选择在何时用throw抛出异常
3、运行时异常和普通异常有什么区别?
Java提供了两种错误的异常类:Error和Exception,并且它们都有共同的父类 - Throwable
Error:
Error表示程序在运行期间出现了非常严重的错误,并且该错误是不可恢复的,由于这属于JVM
层次的错误,故这种错误会导致程序终止执行。此外编译器不会检查Error是否被处理,因此在
程序中不推荐去捕获Error类型的异常,主要是由于Error多是应该解决的错误,一个正确的程序
不应该存在Error,OutOfMemoryErro、ThreadDeath等都属于错误,当这些异常发生时JVM一般
会选择将线程终止
Exception:
Exception表示可恢复的异常,是编译器可以捕捉到的,包含两种类型:检查异常和运行时异常
检查异常:发生在编译阶段,Java编译器强制程序去捕获此类型的异常即把可能会出现这种异常的代码放在
try块中,把对异常处理的代码放到catch代码块中。常见的检查异常有IO异常和SQL异常
运行时异常:编译器并没有强制对其进行捕获并处理,如果不对这种异常进行处理,当出现这种异常时会由
JVM来处理。常见的运行时异常有NullPointerException、ClassCastException等异常
引申 - 使用异常的注意点:
- 进行异常捕获,先捕获子类再捕获基类
- 尽早抛出异常,同时对捕获的异常进行处理
- 可以根据需要自定义异常类,只要继承Exception类即可
- 异常能处理就处理,不能处理就抛出