28.JAVA编程思想——用finally清除

28.JAVA编程思想——用finally清除

无论一个违例是否在try 块中发生,我们经常都想执行一些特定的代码。对一些特定的操作,经常都会遇到这种情况,但在恢复内存时一般都不需要(因为垃圾收集器会自动照料一切)。为达到这个目的,可在所有违例控制器的末尾使用一个finally 从句。所以完整的违例控制小节象下面这个样子:

try {

// 要保卫的区域:

// 可能“掷”出A,B,或C 的危险情况

} catch (A a1) {

// 控制器 A

} catch (B b1) {

// 控制器 B

} catch (C c1) {

// 控制器 C

} finally {

// 每次都会发生的情况

}

演示finally 从句

1     代码如下

publicclass FinallyWorks {

    staticintcount= 0;

    publicstaticvoidmain(String[]args){

        while (true) {

            try {

                // post-increment is zero first time:

                if (count++ == 0)

                    thrownew Exception();

                System.out.println("No exception");

            } catch (Exceptione) {

                System.out.println("Exception thrown");

            } finally {

                System.out.println("in finally clause");

                if (count == 2)

                    break;// out of "while"

            }

        }

    }

} /// :~

 

2     执行如下

Exceptionthrown

infinally clause

Noexception

infinally clause

通过该程序,可知道如何应付Java 违例(类似C++的违例)不允许我们恢复至违例产生地方的这一事实。若将自己的try 块置入一个循环内,就可建立一个条件,它必须在继续程序之前满足。亦可添加一个static计数器或者另一些设备,允许循环在放弃以前尝试数种不同的方法。这样一来,我们的程序可以变得更加“健壮”。

无论是否“掷”出一个违例,finally 从句都会执行。

3     用f i n a l l y 做什么

在没有“垃圾收集”以及“自动调用破坏器”机制的一种语言中,finally显得特别重要,因为

程序员可用它担保内存的正确释放——无论在try 块内部发生了什么状况。但Java 提供了垃圾收集机制,所以内存的释放几乎绝对不会成为问题。另外,它也没有构建器可供调用。既然如此,Java 里何时才会用到finally 呢?

 “破坏器”(Destructor)是“构建器”(Constructor)的反义词。它代表一个特殊的函数,一旦某个对象失去用处,通常就会调用它。我们肯定知道在哪里以及何时调用破坏器。C++提供了自动的破坏器调用机制,但Delphi 的Object Pascal 版本1 及2却不具备这一能力(在这种语言中,破坏器的含义与用法都发生了变化)。

除将内存设回原始状态以外,若要设置另一些东西,finally 就是必需的。例如,我们有时需要打开一个文件或者建立一个网络连接,或者在屏幕上画一些东西,甚至设置外部世界的一个开关,等等。如

3.1     代码1

class Switch {

    booleanstate= false;

    boolean read() {

        returnstate;

    }

    void on() {

        state =true;

    }

    void off() {

        state =false;

    }

}

publicclass OnOffSwitch {

    static Switchsw= newSwitch();

    publicstaticvoidmain(String[]args){

        try {

            sw.on();

            // Code that can throw exceptions...

            sw.off();

        } catch (NullPointerExceptione) {

            System.out.println("NullPointerException");

            sw.off();

        } catch (IllegalArgumentExceptione) {

            System.out.println("IOException");

            sw.off();

        }

    }

} /// :~

3.2     说明

这里的目标是保证main()完成时开关处于关闭状态,所以将sw.off()置于try 块以及每个违例控制器的末尾。但产生的一个违例有可能不是在这里捕获的,这便会错过sw.off()。然而,利用finally,我们可以将来自try 块的关闭代码只置于一个地方:

3.3     代码2

class Switch2 {

    booleanstate= false;

    boolean read() {

        returnstate;

    }

    void on() {

        state =true;

    }

    void off() {

        state =false;

    }

}

publicclass WithFinally {

    static Switch2sw= newSwitch2();

    publicstaticvoidmain(String[]args){

        try {

            sw.on();

            // Code that can throw exceptions...

        } catch (NullPointerExceptione) {

            System.out.println("NullPointerException");

        } catch (IllegalArgumentExceptione) {

            System.out.println("IOException");

        } finally {

            sw.off();

        }

    }

} /// :~

3.4     说明

sw.off()已移至一个地方。无论发生什么事情,都肯定会运行它。

即使违例不在当前的catch 从句集里捕获,finally 都会在违例控制机制转到更高级别搜索一个控制器之前得以执行。如下所示:

3.5     代码3

classEx extends Exception {

}

publicclass AlwaysFinally {

    publicstaticvoidmain(String[]args){

        System.out.println("Entering first try block");

        try {

            System.out.println("Entering second try block");

            try {

                thrownew Ex();

            } finally {

                System.out.println("finally in 2nd try block");

            }

        } catch (Exe) {

            System.out.println("Caught Ex in first try block");

        } finally {

            System.out.println("finally in 1st try block");

        }

    }

} /// :~

3.6     输出:

Enteringfirst try block

Enteringsecond try block

finallyin 2nd try block

CaughtEx in first try block

finallyin 1st try block

若调用了break 和continue语句,finally 语句也会得以执行。请注意,与作上标签的break和continue一道,finally 排除了Java 对goto 跳转语句的需求。

4     缺点:丢失的违例

一般情况下,Java 的违例实施方案都显得十分出色。不幸的是,它依然存在一个缺点。尽管违例指出程序里存在一个危机,而且绝不应忽略,但一个违例仍有可能简单地“丢失”。在采用finally 从句的一种特殊配置下,便有可能发生这种情况:

4.1     代码

classVeryImportantException extends Exception {

    public String toString() {

        return"A very important exception!";

    }

}

classHoHumException extends Exception {

    public String toString() {

        return"A trivial exception";

    }

}

publicclass LostMessage {

    void f()throwsVeryImportantException {

        thrownew VeryImportantException();

    }

    void dispose()throws HoHumException {

        thrownew HoHumException();

    }

    publicstaticvoidmain(String[]args)throwsException {

        LostMessage lm =new LostMessage();

        try {

            lm.f();

        } finally {

            lm.dispose();

        }

    }

} /// :~

4.2     执行

Exceptionin thread "main" A trivial exception

    at LostMessage.dispose(LostMessage.java:19)

    at LostMessage.main(LostMessage.java:27)

可以看到,这里不存在VeryImportantException(非常重要的违例)的迹象,它只是简单地被finally 从句中的HoHumException 代替了。这是一项相当严重的缺陷,因为它意味着一个违例可能完全丢失。而且就象前例演示的那样,这种丢失显得非常“自然”,很难被人查出蛛丝马迹。而与此相反,C++里如果第二个违例在第一个违例得到控制前产生,

就会被当作一个严重的编程错误处理。或许Java 以后的版本会纠正这个问题(上述结果是用Java 而与此相反,C++里如果第二个违例在第一个违例得到控制前产生,就会被当作一个严重的编程错误处理。或许Java 以后的版本会纠正这个问题。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值