1. try-catch
使用try和catch关键字可以捕获异常,通常try-catch代码块放在异常可能发生的地方,用以保护代码稳定运行:
try {// 程序代码} catch (ExceptionName e) {// catch代码块}
catch语句包含要捕获异常类型的声明,当try代码块中发生异常时,catch块就会被检查。如果发生的异常包含在catch块中,异常则会被传递到该catch块,本质上和传递参数给方法是一样的。
如果一个try代码块跟随多个catch代码块,我们称之为多重捕获。
try {// 程序代码} catch (ExceptionName1 e1) {// catch代码块} catch (ExceptionName2 e2) {// catch代码块} catch (ExceptionName3 e3) {// catch代码块}
💡
catch代码块要先将作用范围小的放在前面,作用范围大的依次往后放。如果一开始就捕获Exception的话,那么其他异常都不会被捕获了。
2. throws/throw
如果一个方法没有捕获一个检查性异常,那么该方法必须使用throws关键字来声明。throws关键字放在方法签名的尾部,也可以使用throw关键字抛出一个异常。同时,一个方法也可以声明抛出多个异常,异常之间使用逗号隔开。
| ```java public static void main(String[] args) throws InterruptedException{}
| ```javapublic static void main(String[] args)throws InterruptedException, IOException {}
| | —- | —- |
3. finally
finally关键字用来创建try代码块后面执行的代码块,无论异常是否发生,finally代码块总是会被执行。在finally代码块中,可以执行收尾性代码。另外,finally代码块出啊先在catch代码块的最后。
try {// 程序代码} catch (ExceptionName1 e1) {// catch代码块} catch (ExceptionName2 e2) {// catch代码块} finally {// finally代码块}
以下情况下,finally代码块不会被执行:
- 在
finally代码块中发生了异常,那么该代码块不会被完整地执行 - 在前面的代码中使用了
System.exit()退出了程序 - 程序所在线程死亡
-
4. try-catch-finally执行顺序
| ```java public class TryCatchFinally { public static int test() {
int i = 1;try {i++;System.out.println("Try i = " + i);} catch (Exception e) {i--;System.out.println("Catch i = " + i);} finally {i = 10;System.out.println("Finally i = " + i);}return i;
}
public static void main(String[] args) {
int result = test();System.out.println(result);
} }
// Try i = 2 // Finally i = 10 // 10
| ```javapublic class TryCatchFinally {public static int test() {int i = 1;try {i++;System.out.println("Try i = " + i);throw new Exception();} catch (Exception e) {i--;System.out.println("Catch i = " + i);} finally {i = 10;System.out.println("Finally i = " + i);}return i;}public static void main(String[] args) {int result = test();System.out.println(result);}}// Try i = 1// Finally i = 10// 10
| | —- | —- | | ```java public class TryCatchFinally { public static int test() { int i = 1; try { i++; System.out.println(“Try i = “ + i); return i; } catch (Exception e) { i—; System.out.println(“Catch i = “ + i); } finally { i = 10; System.out.println(“Finally i = “ + i); } return i; }
public static void main(String[] args) {int result = test();System.out.println(result);}
}
// Try i = 2 // Finally i = 10 // 2
| ```javapublic class TryCatchFinally {public static int test() {int i = 1;try {i++;System.out.println("Try i = " + i);return i;} catch (Exception e) {i--;System.out.println("Catch i = " + i);return i;} finally {i = 10;System.out.println("Finally i = " + i);return i;}}public static void main(String[] args) {int result = test();System.out.println(result);}}// Try i = 2// Finally i = 10// 3
|
如果finally代码块中包含return语句,那么程序将直接忽略try代码块中的return语句。
- 对于异常的使用有一个不成文的约定:尽量在某个集中的位置进行统一处理,不要到处使用
try-catch,否则代码会变得混乱不看。 - 按照程序员的惯性认知,当遇到
return语句的时候,执行函数会立刻返回。但是在 JAVA 语言中,如果存在finally代码块的话就会有例外。除了return语句,try代码块中break或者continue语句也可能使控制权进入finally代码块。 - 不要在
try代码块中调用return、break或者continue语句,万一无法避免,一定要确保finally的存在不会改变方法的返回值。 - 方法返回值有两种类型:值类型与对象引用。对于对象引用,要特别小心,如果在
finally代码块中返回的对象成员属性进行了修改,即使不在finally块中显式调用return语句,这个修改也会作用在返回值上。
:::info 💡 注意点:
- 尽量不要捕获类似
Exception这样的通用异常,而是应该捕获特定异常。 - 不要生吞异常,这是异常处理中特别需要注意的事情,否则将导致难以诊断的诡异情况,该抛出异常时还是应该将异常抛出,以便后续代码的优化。 :::
