1 Java 异常简介
众所周知,Java 的所有异常都派生自 Throwable 类,在继承结构上,从 Throwable 派生出了 Error 和 Exception 两大类。其中,Error 表示系统级别的严重程序错误,一般由 JVM 抛出,我们也不应该捕获这类异常,用户自定义的异常一般都派生自 Exception 类。
从是否被编译器强制检查一点,异常又可分为受检异常(Checked Exception)和未受检异常(Unchecked Exception)。未受检异常派生自 Error 或者 RuntimeException,表示不可恢复的程序错误,典型例子有 AssertionError、NullPointerException 等,编译器不会强制我们捕获这类异常。受检异常则是除了 Error/RuntimeException 之外,派生自 Throwable 或者 Exception 的其他异常,比如 IOException、SQLException 等。
如果一个方法声明自己可能抛出受检异常,那么编译器会强制它的调用者必须使用 try-catch 捕获此异常,或者在自己的方法中加上 throws 声明将异常继续传播给外界。 除非抛出RuntimeException或其子类,可在外部进行异常捕获。
多年以来,Java 中受检异常的设计一直颇受争议,反对者认为,受检异常容易破坏方法声明的兼容性,会使代码的可读性降低,还增加开发的工作量等等。当然也有一些支持者,他们认为受检异常可以强迫程序员去思考,有助于他们写出更健壮的代码,可以参考王垠的文章「Kotlin 和 Checked Exception」。
2 java 中的异常处理实例
直接上代码,先贴下面测试需要调用的方法:
// catch 后续处理工作
public static boolean catchMethod() {
System.out.print("call catchMethod and return --->> ");
return false;
}
// finally后续处理工作
public static void finallyMethod() {
System.out.println();
System.out.print("call finallyMethod and do something --->> ");
}
1. 抛出 Exception,没有 finally,当 catch 遇上 return
public static boolean catchTest() {
try {
int i = 10 / 0; // 抛出 Exception,后续处理被拒绝
System.out.println("i vaule is : " + i);
return true; // Exception 已经抛出,没有获得被执行的机会
} catch (Exception e) {
System.out.println(" -- Exception --");
return catchMethod(); // Exception 抛出,获得了调用方法并返回方法值的机会
}
}
后台输出结果:
-- Exception --
call catchMethod and return --->> false
2. 抛出 Exception,当 catch 体里有 return,finally 体的代码块将在 catch 执行 return 之前被执行
public static boolean catchFinallyTest1() {
try {
int i = 10 / 0; // 抛出 Exception,后续处理被拒绝
System.out.println("i vaule is : " + i);
return true; // Exception 已经抛出,没有获得被执行的机会
} catch (Exception e) {
System.out.println(" -- Exception --");
return catchMethod(); // Exception 抛出,获得了调用方法的机会,但方法值在 finally 执行完后才返回
}finally{
finallyMethod(); // Exception 抛出,finally 代码块将在 catch 执行 return 之前被执行
}
}
后台输出结果:
-- Exception --
call catchMethod and return --->>
call finallyMethod and do something --->> false
3. 不抛 Exception,当 finally 代码块里面遇上 return,finally 执行完后将结束整个方法
public static boolean catchFinallyTest2() {
try {
int i = 10 / 2; // 不抛出 Exception
System.out.println("i vaule is : " + i);
return true; // 获得被执行的机会,但执行需要在 finally 执行完成之后才能被执行
} catch (Exception e) {
System.out.println(" -- Exception --");
return catchMethod();
}finally{
finallyMethod();
return false; // finally 中含有 return 语句,这个 return 将结束这个方法,不会在执行完之后再跳回 try 或 catch 继续执行,方法到此结束,返回 false
}
}
后台输出结果:
i vaule is : 5
call finallyMethod and do something --->> false
4. 不抛 Exception,当 finally 代码块里面遇上 System.exit() 方法 将结束和终止整个程序,而不只是方法
public static boolean finallyExitTest() {
try {
int i = 10 / 2; // 不抛出 Exception
System.out.println("i vaule is : " + i);
return true; // 获得被执行的机会,但由于 finally 已经终止程序,返回值没有机会被返回
} catch (Exception e) {
System.out.println(" -- Exception --");
return true;
}finally {
finallyMethod();
System.exit(0);// finally 中含有 System.exit() 语句,System.exit() 将退出整个程序,程序将被终止
}
}
后台输出结果:
i vaule is : 5
call finallyMethod and do something --->>
5. 抛出 Exception,当 catch 和 finally 同时遇上 return,catch 的 return 返回值将不会被返回,finally 的 return 语句将结束整个方法并返回
public static boolean finallyTest1() {
try {
int i = 10 / 0; // 抛出 Exception,后续处理被拒绝
System.out.println("i vaule is : " + i);
return true; // Exception 已经抛出,没有获得被执行的机会
} catch (Exception e) {
System.out.println(" -- Exception --");
return true; // Exception 已经抛出,获得被执行的机会,但返回操作将被 finally 截断
}finally {
finallyMethod();
return false; // return 将结束整个方法,返回 false
}
}
后台输出结果:
-- Exception --
call finallyMethod and do something --->> false
6. 不抛出 Exception,当 finally 遇上 return,try 的 return 返回值将不会被返回,finally 的 return 语句将结束整个方法并返回
public static boolean finallyTest2() {
try {
int i = 10 / 2; // 不抛出 Exception
System.out.println("i vaule is : " + i);
return true; // 获得被执行的机会,但返回将被 finally 截断
} catch (Exception e) {
System.out.println(" -- Exception --");
return true;
}finally {
finallyMethod();
return false; // return 将结束这个方法,不会在执行完之后再跳回 try 或 catch 继续执行,返回 false
}
}
后台输出结果:
i vaule is : 5
call finallyMethod and do something --->> false
结语:
java 的异常处理中(假设方法需要返回值):
- 在不抛出异常的情况下,程序执行完 try 里面的代码块之后,该方法并不会立即结束,而是继续试图去寻找该方法有没有 finally 的代码块,
- 如果没有 finally 代码块,整个方法在执行完 try 代码块后返回相应的值来结束整个方法;
- 如果有 finally 代码块,此时程序执行到 try 代码块里的 return 语句之时并不会立即执行 return,而是先去执行 finally 代码块里的代码,
- 若 finally 代码块里没有 return 或没有能够终止程序的代码,程序将在执行完 finally 代码块代码之后再返回 try 代码块执行 return 语句来结束整个方法;
- 若 finally 代码块里有 return 或含有能够终止程序的代码,方法将在执行完 finally 之后被结束,不再跳回 try 代码块执行 return。
在抛出异常的情况下,原理也是和上面的一样的,你把上面说到的 try 换成 catch 去理解就 OK 了 *_*
###################
java异常处理-finally中使用return和throw语句
java异常语句中的finally块通常用来做资源释放操作,如关闭文件、关闭网络连接、关闭数据库连接等。正常情况下finally语句中不应该使用return语句也不应该抛出异常,以下讨论仅限于java语言设计本身,正常编码时应避免。
finally块中使用return会覆盖method的返回值
以下代码的返回值为:1
public static int div(){
try {
return 3;
}catch (ArithmeticException e){
System.out.println("catch in div");
return 2;
}
finally {
System.out.println("finally in div");
return 1;
}
}
以下代码的返回值同样是:1
public static int div(){
try {
return 3/0;
}catch (ArithmeticException e){
System.out.println("catch in div");
return 2;
}
finally {
System.out.println("finally in div");
return 1;
}
}
finally块中使用return会抑制异常的冒泡传输
即:只要finally中使用了return语句,调用者便认为该方法正常返回
以下代码
/**
* Created by Administrator on 2017/11/27.
*/
public class Test {
public static void main(String[] args) {
adapter();
}
public static void adapter() {
try {
div();
} catch (ArithmeticException e) {
System.out.println("catch in adapter");
} finally {
System.out.println("finally in adapter");
}
}
public static int div() {
try {
int a = 5 / 0;
return a;
} catch (ArithmeticException e) {
System.out.println("catch in div");
throw e; // 重新将异常抛出给调用者
} finally {
System.out.println("finally in div");
}
}
}
输出为
catch in div
finally in div
catch in adapter
finally in adapter
但如果在 div 的finally块中添加了return语句
public static int div(){ try { int a = 5/0; return a; }catch (ArithmeticException e){ System.out.println("catch in div"); throw e; // 重新将异常抛出给调用者,但是抛出会被忽略 } finally { System.out.println("finally in div"); return 1; } }
则代码的输出为
catch in div
finally in div
finally in adapter
即:finally块中的return语句会阻止异常的栈调用传输,使caller认为该方法已经正常返回
finally块中的throw语句会覆盖try和catch语句中的异常
以下代码
/** * Created by Administrator on 2017/11/27. */ public class Test { public static void main(String[] args) { adapter(); } public static void adapter() { try { div(); } catch (Exception e) { System.out.println(String.format("catch in adapter: %s",e.getMessage())); } finally { System.out.println("finally in adapter"); } } public static int div() throws Exception{ try { int a = 5 / 0; return a; } catch (ArithmeticException e) { System.out.println("catch in div"); throw new Exception("Exception in div"); // 抛出新的异常 } finally { System.out.println("finally in div"); throw new Exception("Exception in Finally"); // 抛出新的异常 } } }
输出是:
catch in div
finally in div
catch in adapter: Exception in Finally
finally in adapter
即,catch块中抛出的异常北finally块抛出的异常替换了
修改div方法为
public static int div() throws Exception{ try { int a = 5 / 0; return a; } finally { System.out.println("finally in div"); throw new Exception("Exception in Finally"); // 抛出新的异常 } }
输出为:
finally in div
catch in adapter: Exception in Finally
finally in adapter
即,try块中捕获的异常北finally块抛出的异常替换