Java Puzzlers(4)异常之谜

周末了,有时间更新一下。周末好象也没什么特别,除了多睡点和看看书之外,无事可做,可怜的单身生涯。

异常,复杂的话题了。

一。首先看看下面这个例子,到底返回true还是false呢?还是根本编译不通过:

public class Indecisive {
    public static void main(String[] args) {
        System.out.println(decision());
    }

    static boolean decision() {
        try {
           return true;
        } finally {
            return false;
        }
    }
}

答案是false,finaly语句块总是在程序控制权从try块离开时开始执行,无论try语句块中是以正常方式或者意外行为结束。当try块与finaly块都以意外方式结束,整个try..finaly的意外结束的原因将与finaly语句块意外结束的原因相同,即try块意外结束的原因将被抛弃。对于finaly的使用,需要记住:

每一个finaly语句块都应该被正常结束,除非抛出非受控异常。在finaly语句块中不应该使用break,continue,return或者throw来退出,不应当让受控异常传播到finaly之外。

等等,我们再来看个例子,下面的finaly块会被执行吗??

public class HelloGoodbye {
    public static void main(String[] args) {
        try {
            System.out.println("Hello world");
            System.exit(0);
        } finally {
            System.out.println("Goodbye world");
        }
    }
}

很抱歉,它只打印:Hello World,finaly语句并没有被执行,这是为何?这是因为System.exit方法将立刻终止当前程序的所有线程,使得finaly块根本没机会被调用。System.exit执行两步操作,首先就是停止当前所有线程,其次就是在关闭VM之前执行Shut down Hook(关闭挂钩)。如果我们希望在VM关闭之前执行一些操作,这些操作应该在Runtime.addShutDownHook上注册,因此,上面的程序可以修改为:

public class HelloGoodbye {
    public static void main(String[] args) {
  
       System.out.println("Hello world");
       Runtime.getRuntime().addShutdownHook(
               new Thread(){
           public void run(){
                System.out.println("Goodbye world");
           }
       });
       System.exit(0);
    }
}

 

二。来看看一些不可思议的程序。

第一个程序:

import java.io.IOException;

public class Arcane1 {
    public static void main(String[] args) {
        try {
            System.out.println("Hello world");
        } catch(IOException e) {
            System.out.println("I've never seen println fail!");
        }
    }
}

试着编译下,sorry,不能通过。报错:

在相应的try语句主体中不能抛出异常java.io.IOException

错误信息已经很明显地告诉我们原因了,System.out.println方法并不能抛出受控异常IOException。这在JAVA语言规范中已经有描述,如果catch所捕捉的受控异常在try块里并不能被抛出,这将是一个编译期错误!

第2个程序:

public class Arcane2 {
    public static void main(String[] args) {
        try {
        } catch(Exception e) {
            System.out.println("This can't happen");
        }
    }
}

编译竟然通过了,这不是跟我们第一个程序得到的结论有矛盾??这又是因为JAVA语言规范所决定的,捕获Exception或者Throwable的catch语句都是合法,不管他们的try块语句的内容是什么。特例,特例^_^

第3个程序,有点长了,首先定义3个接口:

interface Type1 {
    void f() throws CloneNotSupportedException;
}

interface Type2 {
    void f() throws InterruptedException;
}

interface Type3 extends Type1, Type2 {
}

接口Type3继承Type1,Type2(JAVA中接口是可以多重继承的),Type1,Type2的f()方法各抛出一个受控异常。接着看:

public class Arcane3 implements Type3 {
    public void f() {
        System.out.println("Hello world");
    }

    public static void main(String[] args) {
        Type3 t3 = new Arcane3();
        t3.f();
    }
}

编译通过,打印Hello World!可是我明明声明了两个受控异常啊,怎么实现类都不用处理了??不是要放在一个try..catch块里面才行??原因就在于一个方法可以抛出的受控异常的集合是它所适用所有类型(即父类型,此例中的Type1,Type2)声明要抛出的受控异常的交集,而不是并集!

 

三。初始化与异常。构造函数必须声明其实例初始化操作中会抛出的所有受控异常。类中值域的初始化操作是在调用构造函数之前发生的。不要滥用异常,比如使用异常去控制循环,应该只为异常条件而使用异常。

四。删除类,书中的谜题44,我不能完全理解,待续,如有朋友有好的见解,最好共享下。

五。以一个看似会无限循环的递归程序结尾,其实因为JVM的栈的深度有限,此程序总会终结,可时间恐怕要在你我骨灰已经历N个物质循环之后:

public class Workout {
    public static void main(String[] args) {
        workHard();
        System.out.println("It's nap time.");
    }

    private static void workHard() {
        try {
            workHard();
        } finally {
            workHard();
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值