JAVA中的finally及异常丢失问题

来源:互联网 发布:苹果手机搞怪软件 编辑:程序博客网 时间:2024/06/06 04:04

在某些程序当中,我们通常会希望无论try块中的异常是否抛出,它们都能够得到执行。通常适用于内存回收之外的情况,为了达到此效果,可以在异常处理程序之后加入finally语句,finally子句总能够得到执行,看下面一段代码:

package access;class ThreeException extends Exception{}public class FinallyWorks {static int count = 0;public static void main(String[] args) {// TODO Auto-generated method stubwhile(true){try{if(count++ == 0)throw new ThreeException();System.out.println("No exception");}catch(ThreeException t){System.out.println("ThreeException");}finally{System.out.println("In finally clause");if(count == 2) break;}}}}
此程序的输出结果为:


从输出结果中可以看到,finally子句始终被执行,当JAVA中的异常不允许我们返回到异常抛出点时,我们可以将try块放入while循环中,建立一个程序执行之前必须要达到的条件;还可以加入一个static计数器,使循环在放弃之前可以执行一定的次数。

JAVA有垃圾回收机制,内存释放不再是问题,JAVA也没有析构函数可以调用,finally的用处在于:将要把除内存之外的资源恢复到它们的初始状态时就需要用到finally子句,通常包括已经打开的文件或网络连接、在屏幕上画的某个图形、外部世界的某个开关。看下面一段代码:

package access;import java.util.*;public class Switch {private boolean state =  false;public boolean read(){return state;}public void on(){state = true;System.out.println(this);}public void off(){state = false;System.out.println(this);}public String toString(){return state?"on":"off";}class OnOffException1 extends Exception{}class OnOffException2 extends Exception{}private static Switch sw = new Switch();static void f() throws OnOffException1,OnOffException2{}public static void main(String[] args) {// TODO Auto-generated method stubtry{sw.on();f();sw.off();}catch(OnOffException1 e){System.out.println("OnOffException1");sw.off();}catch(OnOffException2 e){System.out.println("OnOffException2");sw.off();}}}
此程序的输出结果为:


程序的目的是确保main方法结束时开关必须是关着的,所以在catch中加入了sw.off()。但是也有可能发生异常被抛出却并没有被处理程序捕获的情况,这时sw.off()就得不到调用,所以加入finally来确保这种情况的不会发生:

package access;import access.Switch.*;public class WithFinally {static Switch sw = new Switch();public static void main(String[] args) {// TODO Auto-generated method stubtry{sw.on();Switch.f();}catch(OnOffException1 e){System.out.println("OnOffException1");}catch(OnOffException2 e){System.out.println("OnOffException2");}finally{sw.off();}}}
此程序的输出结果为:


在此种情况下,即使异常没有被当前的异常处理程序捕获,异常处理机制也会跳到高一层的异常处理程序之前执行finally子句。当涉及break和continue子句时,finally子句也同样会得到执行,如果把finally子句和带标签的break和continue子句配合使用的时候,就没必要使用goto子句了。

由于finally子句总是会执行,所以在一个方法中,可以从多点返回并且保证重要的清理工作的正常进行,看如下一段代码:

package access;import java.util.*;public class MultipleReturns {public static void f(int i){System.out.println("Initialization that requires cleanup");try{System.out.println("Point 1");if(i == 1)return;System.out.println("Point 2");if(i == 2)return;System.out.println("Point 3");if(i == 3)return;System.out.println("End");return;}finally{System.out.println("Performing cleanup");}}public static void main(String[] args) {// TODO Auto-generated method stubfor(int i = 1;i <= 4; i++)f(i);}}
此程序的输出结果为:


从输出结果中可以看到,在finally内部,从何处返回并不重要。

另外,不带返回值的return语句只能用于返回类型为void类型的函数,作用是引起函数的强制结束,类似循环结构中的break语句。

尽管看上去JAVA的异常机制是如此合理,但依然有一些问题,最典型的就是异常丢失的问题。异常作为程序出错的标志,不应该被忽略任何一个,但是在某些情况下,它依然会被忽略掉,比如如下代码段:

package access;class VeryImportantException extends Exception{public String toString(){return "A very important exception!";}}class HoHumException extends Exception{public String toString(){return "A trivial exception!";}}public class LostMessage {void f() throws VeryImportantException{throw new VeryImportantException();}void dispose() throws HoHumException{throw new HoHumException();}public static void main(String[] args) {// TODO Auto-generated method stubtry{LostMessage lm = new LostMessage();try{lm.f();}finally{lm.dispose();}}catch(Exception e){System.out.println(e);}}}
此程序的输出结果为:


由输出可以看出,VeryImportantException被finally中的子句HoHumException取代,这是相当隐蔽并且微妙的丢失异常的缺陷。一直到现在的版本,JAVA仍然没有修复这个问题,而另一种更加简单的丢失异常的方式是从finally中返回,看如下代码:

package access;public class ExceptionSilencer {public static void main(String[] args) {// TODO Auto-generated method stubtry{throw new RuntimeException();}finally{return;}}}
此程序没有任何输出。修改程序:

package access;public class ExceptionSilencer {public static void main(String[] args) {// TODO Auto-generated method stubtry{throw new RuntimeException();}catch(Exception e){System.out.println(e);}}}
此程序的输出结果为:


对比两个程序可知即使抛出了异常,当在finally中使用return语句时异常仍然会丢失。

原创粉丝点击