问题一: 有意思的异常处理
看一下下面的异常处理代码, 猜一下会打印什么呢?
- public static void main(String[] args) {
- System.out.println(decision());
- }
- private static boolean decision() {
- try {
- return true;
- } finally {
- return false;
- }
- }
熟悉 Java 异常处理的你, 可能一眼就看出来了, 结果是打印 false , 如果你觉得会打印 true 的话, 那说明你的基础还是有点小问题的. 虽然这里比较简单, 但我们还是来简单说明下.
解惑 1:
我们既然学过 java 中的异常处理, 那么原因的话也比较简单:
在 try-finally 块中, 无论 try 语句是否是正常结束, 是否抛出异常, 是否直接返回, 最终都会执行 finally 块中的语句;
但有一点需要注意, 如果在 try 语句中执行了 System.exit(0) , 那么便不会走到 finally 块了, 因为该操作会直接停止当前线程.
1. try-finally 顺序问题
我们接着来看 try-finally 的问题, 下面来看下 try-finally 的顺序问题, 看下下面的程序会打印什么?
- public static void main(String[] args) {
- System.out.println(decision());
- }
- private static boolean decision() {
- try {
- System.out.println("---try---");
- return true;
- } finally {
- System.out.println("---finally---");
- }
- }
很显然, 这里 try 语句中使用了 return 语句, 而 finally 中没有 return, 那么最终打印的结果:
- ---try---
- ---finally---
- true
和上面相比, 也就是说
try 会尝试执行 return 语句, 如果 finally 块中没有 return 语句, 那么 try 的尝试将会成功; 如果 finally 中有 return, 那么 try 的尝试将会被 finally 替代.
2. try-catch-finally 的问题
这次我们加入 catch 操作来看下 (main 方法由于都一样, 这里就不贴上来了):
- private static boolean decision() {
- try {
- System.out.println("---try---");
- int temp = 23 / 0;
- return true;
- } catch (Exception e) {
- System.out.println("---catch---");
- return false;
- } finally {
- System.out.println("---finally---");
- }
- }
因为程序有异常, 所以一定会走进 catch 块, 那么最终的打印结果想必大家也知道了:
- ---try---
- ---catch---
- ---finally---
- false
而如果 finally 中也有 return 语句的话呢, 会不会也会覆盖掉 catch 中的 return 呢? 我们简单修改下代码:
- private static boolean decision() {
- try {
- System.out.println("---try---");
- int temp = 23 / 0;
- return true;
- } catch (Exception e) {
- System.out.println("---catch---");
- return true;
- } finally {
- System.out.println("---finally---");
- return false;
- }
- }
没错, 大家的猜想是正确的:
- ---try---
- ---catch---
- ---finally---
- false
3. try-catch-finally 语句相加问题
再来看一下最后一个例子. 猜测一下下面会打印什么呢?
- private static int decision() {
- int temp = 10;
- try {
- System.out.println("--try---");
- return temp += 5;
- } catch (Exception e) {
- System.out.println("---catch---");
- } finally {
- System.out.println("---finally---");
- temp = 25;
- }
- return temp;
- }
这里在进行 try-catch-finally 中的时候虽然有一个运算操作, 不过大家应该一眼就看出来了:
- --try---
- ---finally---
- 15
这个和上面的 try-catch 流程类似, 因为 try 语句中有 return 语句, 所以永远不会走到最下面的 return 语句, 并且因为 finally 里没有 return, 所以无论我们在 finally 里怎么修改 temp 的值, 最终返回的仍然是 try 语句中的 temp 的值.
这里可能还需要注意的就是 return temp += 5 ; 如果 finally 中也有 return 的话, 那么最终将执行 finally 里的 return:
- private static int decision() {
- int temp = 10;
- try {
- System.out.println("--try---");
- return temp += 5;
- } catch (Exception e) {
- System.out.println("---catch---");
- } finally {
- System.out.println("---finally---");
- return temp;
- }
- }
很显然, 这里会执行 finally 块中的 return, 但最终的 temp 的值是由 return temp += 5 这里计算出来的, 这里会分成两步计算: temp + 5; , return temp; , 所以最终返回的 temp 仍然是 15.
问题二: checked 与 unchecked 异常
看下下面的代码会打印什么呢?
- public static void main(String[] args) {
- try {
- System.out.println("Hello World");
- } catch (IOException e) {
- System.out.println("exception");
- }
- }
猜测一下这个程序会打印什么呢, 会打印 Hello World 么? 很遗憾, 这个程序编译不通过, 更谈不上打印些什么了.
解惑 2:
这个问题原因也是很简单, 因为:
Java 语言规范将继承自 Error 类或者 RuntimeException 类的所有异常称为 未检查异常 (unchecked) , 而所有其他的异常则称为 已检查异常 (checked) ;
针对 checked 异常也就是说, 一个方法不仅需要告诉编译器将要返回什么值, 还要告诉编译器有可能发生什么错误 ; 所以 Java 规范要求, 如果 cache 语句要捕获一个 checked 异常, 那么相应的 try 子句便要抛出对应 checked 异常或子类型的异常;
因为 IOException 属于 checked 异常, 所以这里编译不通过;
那么来看一下下面的程序呢, 会打印什么呢?
- public static void main(String[] args) {
- try {
- System.out.println("Hello World");
- } catch (Exception e) {
- System.out.println("exception");
- }
- }
很显然, 这个程序肯定是可以编译通过的, 并且会打印对应的 Hello world , 因为:
在 Java 中, 捕获 Exception 或者 Throwable 的 catch 语句是合法的; 因为 Exception 本身是个基础类, 不属于 unchecked 异常, 也不属于 checked 异常, 在 Java 中直接捕获 Exception 或者 Throwable 的都是没问题的;
那我们再来看一下面的程序, 最终会通过编译么?
- public class Main implements Type3{
- public static void main(String[] args) {
- Type3 main = new Main();
- main.f();
- }
- @Override
- public void f() {
- System.out.println("hello world");
- }
- }
- interface Type1 {
- void f() throws IOException;
- }
- interface Type2 {
- void f() throws InterruptedException;
- }
- interface Type3 extends Type1, Type2 {}
首先, IOException 和 InterruptedException 都是 checked 异常, Type3 继承自上面这两个接口, 看上去应该编译不通过. 但很遗憾, 这个程序不但可以编译通过, 而且运行没有问题. 虽然我们在学习异常的时候, 了解到:
一个方法要么捕获其方法体可以抛出的所有受检查异常, 要么声明它将抛出这些异常;
就本例而言, Main 调用了 f() 方法, 但却没有处理这两个受检查异常, 但是:
一个方法可以抛出的受检查异常集合, 是它所适用的所有类型声明要抛出的受检查异常集合的交集, 而不是合集;
简单来说, 这里如果会抛出的话, 只能抛出这两个异常的交集, 但因为没有交集, 所以无需抛出, 自然也能编译通过, 成功运行.
来源: http://www.tuicool.com/articles/6JfyUry