1.先简单介绍一下Java中的错误(Error)和异常(Exception)
在java.lang包中有一个java.lang.Throwable类,这个类是所有错误和异常的父类。
Error:
是Java中所有错误的父类,一般是与虚拟机相关的问题,如系统崩溃,虚拟机错误,动态链接失败等。对于这种任务,通常应用程序无法处理这类错误,也不需要开发人员处理,故应用程序不需要使用cath来捕获Error对象,也无须在throws子句中声明该方法可能出现的Error错误。
Exception:
又分为编译异常(checkedException)和运行异常(RuntimeException)这两种异常。
编译异常:在进行编译时就知道会不会发生异常,如果不对这些异常进行抛出,捕获的话就不能通过编译,比如使用Java的io读流取文件的时候,可能会出现文件不存在的情况;还有调用阻塞方法(wait,sleep),中断阻塞就会在外部调用interrupt,那么就会抛出InterruptedException异常。对于这些异常,系统都是做最坏的打算,必须手动去处理(捕获或者抛出)。否则是无法正常通过编译器的,这种异常才需要try-catch。
运行异常:在运行时会可能会出现的异常,之前不知道。比如数组下标越界(ArrayIndexOutOfBoundsException),空指针异常(NullpointerException),除数为0(ArithmeticException)对于这些异常是否抛出,由用户自己决定,因为本来就不知道会不会出现异常,并不强制要去一定处理。
异常处理过程
有两种方式:try{ }catch{ }finally{ }和throws
把会出现的异常程序放在try块中,出现异常中断当前代码去执行catch{ }中内容,最后执行finally。
throws关键字一般用于方法名后面,一般是开发者不确定会出现什么异常的情况可能有多种,这时加个throws关键字抛出。对于调用这个方法的开发者必须捕获这个异常或者继续throws这个异常,把这个异常传递下去,交给其父亲去处理。
throw一般用于方法中,抛出用户自定义的异常如 throw new MyException("用户自定义异常")
2. finally、return:
a. finally中的代码总是会执行吗?
答:no,(两种情况)如果一个方法内在执行try{}语句之前就已经return了,那么finally语句不会执行了。因为根本没有进入try语句中。 如果在一个try语句中调用System.exit(0);方法,那么就会退出当前java虚拟机,那么finally也就没有执行的机会了。(当然,还有极端的,就是在执行到try突然杀死了,断电了)
b、finally在return之前执行还是在return之后执行?
答:是在return中间执行
public class Test { public static void main(String[] args) { System.out.println(method()); } public static int method(){ int x = 1; try { return x; } catch (Exception e){ return 0; }finally { System.out.println("Test"); ++ x; } } }
结果:先输出Test,下一行为1
执行过程:
首先执行到return方法,就会返回相应的值,把值存在临时栈中。此时临时栈为1。但是并不会立马返回,而是还要执行finally方法,执行完后,调用return,此时不是返回值,而是告诉主程序已经执行完了,可以执行其他方法。但是此时临时栈还是保存的是栈中的值为1。
public class Test { public static void main(String[] args) { System.out.println(method()); } public static int method(){ try { return 1; // System.out.println("Test"); } catch (Exception e){ return 0; }finally { return 2; } // System.out.println("Test"); } }
结果:2
执行过程:
执行到return 1时,临时栈为1,接着执行finally中的return 2, 会覆盖之前的1,所以返回2。
注意:上文的那两句输出程序都到达不了。
没看懂? 再来两道:
public class Test1 { public static void main(String[] args) { System.out.println(method()); } public static int method(){ int a = 0; try { a = 1; return a; }finally { a = 2; System.out.println(a); } } }
输出: 2,1
a = 1存到一个临时栈中,程序不会立即返回,在执行a = 2,时仅仅是覆盖了a的值,但是没有去更新临时栈中返回的那个值。如果在finally中输出a的值,则是覆盖后的值。
public class Test1 { public static void main(String[] args) { System.out.println(method()); } public static int method(){ int a = 0; try { a = 1; return a; }finally { a = 2; return a; } } } /** output: 2 */
finally中也有一个return,此时就会去更新临时栈中的值,执行完finally之后,就会通知主程序返回了,即将临时站中的值取出来。(所以应该知道,finally中最好不要有return,否则程序会提前退出,返回值不是try,catch保存的返回值。)
总结:
1,finally一定会执行,无论是否try..catch。
2,finally前try{ }有return,会先执行return,并保存下来,再执行finally块,最后执行return。
3,finally前try{ }有return,会先执行return,把值保存下来,再执行finally块的return,把值覆盖掉,并返回。
(当然catch块有return是一样的,关键在于return保存在临时栈中,并不立马结束,而是去执行finally块。)