Java解惑学习有感(四)---异常之谜

谜题36:优柔寡断

以下代码:

public class Indecisive {

public static void main(String[] args) {

System.out.println(decision());

}
static boolean decision() {

try {
return true;
} finally {
return false;
}

}

}

将会输出false!

因为程序尝试着(try)返回(return)true,但是它最终(finally)返回(return)的是 false

总之,每一个 finally 语句块都应该正常结束,除非抛出的是不受检查的异常。千万不要用一个return、break、continue 或 throw 来退出一个 finally 语句块,并且千万不要允许将一个受检查的异常传播到一个 finally 语句块之外去。

谜题37:极端不可思议

1、对于捕获被检查异常的 catch 子句,只有在相应的 try 子句可以抛出这些异常时才被允许。

2、对于1的特例,捕获 Exception 或 Throwble 的 catch 子句是合法的,不管与其相对应的 try 子句的内容为何

3、多个继承而来的 throws 子句的交集,将减少而不是增加方法允许抛出的异常数量。

谜题38:不受欢迎的宾客

1、 Java 不允许静态初始化操作抛出被检查异常,所以初始化必须包装在 try-finally 语句块中。

2、要确定一个程序是否可以不止一次地对一个空 final 进行赋值是一个很困难的问题。事实上,这是不可能的。这等价于经典的停机问题,它通常被认为是不可能解决的。为了能够编写出一个编译器,语言规范在这一点上采用了保守的方式。

3、如果必须重构一个程序,以消除由明确赋值规则所引发的错误,那么应该考虑添加一个新方法。这样做除了可以解决明确赋值问题,还可以使程序的可读性提高。

谜题39:您好,再见!

以下代码将会打印什么呢?

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。

System.exit 将立即停止所有的程序线程,它并不会使 finally 语句块得到调用,但是它在停止 VM 之前会执行关闭挂钩操作。当 VM 被关闭时,请使用关闭挂钩来终止外部资源。通过调用System.halt 可以在不执行关闭挂钩的情况下停止 VM,但是这个方法很少使用。

谜题40:不情愿的构造器

实例初始化操作是先于构造器的程序体而运行的。实例初始化操作抛出的任何异常都会传播给构造器。如果初始化操作抛出的是被检查异常,那么构造器必须声明也会抛出这些异常,但是应该避免这样做,因为它会造成混乱。最后,对于我们所设计的类,如果其实例包含同样属于这个类的其他实例,那么对这种无限递归要格外当心。

谜题41:域和流

当你在 finally 语句块中调用 close 方法时,要用一个嵌套的 try-catch语句来保护它,以防止IOException 的传播。更一般地讲,对于任何在 finally语句块中可能会抛出的被检查异常都要进行处理,而不是任其传播。这是谜题36 中的教训的一种特例,而对语言设计着的教训情况也相同。

谜题42:异常为循环而抛

1、& 操作符有其他的含义。除了常见的被当作整型操作数的位 AND 操作符之外,当被用于布尔操作数时,它的功能被重载为逻辑 AND 操作符。这个操作符与更经常被使用的条件 AND 操作符有所不同,& 操作符总是要计算它的两个操作数,而 && 操作符在其左边的操作数被计算为 false 时,
就不再计算右边的操作数了。

2、不要去用那些可怕的使用异常而不是使用显式的终止测试的循环惯用法,因为这种惯用法非常不清晰,而且会掩盖 bug。

3、要意识到逻辑 AND 和 OR 操作符的存在,并且不要因无意识的误用而受害。


谜题43:异常地危险

1、警告信息是编译器所采用的一种手段,用来告诉你:你可能正在搬起石头砸自己的脚,而且事实也正是如此。“不受检查的转型”警告告诉你这个有问题的转型将不会在运行时刻受到检查。当你获得了一个不受检查的转型警告时,你应该修改你的程序以消除它,或者你可以确信这个转型不会失败。如果你不这么做,那么某个其他的转型可能会在未来不确定的某个时刻失败,而你也就很难跟踪此错误到其源头了。

2、Java 的异常检查机制并不是虚拟机强制执行的。它只是一个编译期工具,被设计用来帮助我们更加容易地编写正确的程序,但是在运行期可以绕过它。要想减少你因为这类问题而被曝光的次数,就不要忽视编译器给出的警告信息。

谜题44:切掉类

不要对捕获 NoClassDefFoundError 形成依赖。语言规范非常仔细地描述了类初始化是在何时发生的,但是类被加载的时机却显得更加不可预测。更一般地讲,捕获 Error 及其子类型几乎是完全不恰当的。这些异常是为那些不能被恢复的错误而保留的。

谜题45:令人疲惫不堪的测验

研究以下代码:

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();

}

}

}

main 方法调用 workHard,而它又从其 try 语句块中递归地调用了自己,然后它再一次从其 try 语句块中调用了自己。在此时,为了方便说明,假设栈的深度是只有 3。当 workHard 方法试图从其 try 语句块中再次调用自己时,该调用立即就会以StackOverflowError 而失败。这个错误是在最内部的 finally 语句块中被捕获的,在此处栈的深度已经达到了 3。在那里,workHard 方法试图递归地调用它自己,但是该调用却以 StackOverflowError 而失败。这个错误将在上一级的finally 语句块中被捕获,在此处站的深度是 2。该 finally 中的调用将与相对应的 try 语句块具有相同的行为:最终都会产生一个 StackOverflowError。这似乎形成了一种模式,而事实也确实如此



如果有疑问或者对该博文有何看法或建议或有问题的,欢迎评论,恳请指正!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值