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{}
| ```java
public 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
| ```java
public 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
| ```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);
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
这样的通用异常,而是应该捕获特定异常。 - 不要生吞异常,这是异常处理中特别需要注意的事情,否则将导致难以诊断的诡异情况,该抛出异常时还是应该将异常抛出,以便后续代码的优化。 :::