文章目录
- 前言
- JAVA异常体系结构
- JAVA中的异常处理方式
- 注意事项
-
- 避免在finally中使用return
- [受查异常 / 编译时异常不能单独使用 throw](#受查异常 / 编译时异常不能单独使用 throw)
- [非受查异常 / 运行时异常可单独使用throw](#非受查异常 / 运行时异常可单独使用throw)
前言
Java 异常机制是 Java 语言中用于处理程序运行时错误的一套完备体系。它将错误从正常的业务逻辑中分离出来,使得代码更健壮、可读性更高。下面从几个核心方面进行详细解释。
异常(Exception) 是指程序在执行过程中出现的非正常状况(例如除零、数组越界、文件不存在等)。Java 使用面向对象的方式来描述异常:每种异常都是 Throwable 类的子类的一个对象。当异常发生时,JVM 会创建一个异常对象,并抛出(throw);我们可以捕获(catch)并处理它。
JAVA异常体系结构
JAVA中的异常都来自于Throwable,Throwable 又派生出两个子类:一类是 Error 错误,另一类是 Exception 异常。其中 Error 指的是 JAVA 运行时内部错误和资源耗尽错误,这种内部错误一旦出现,除了告知用户并终止程序外别无他法。Exception又可以分为非受查异常(运行时异常)、受查异常(编译时异常)。
- 受查异常 / 编译时异常:编译器强制要求处理(要么 try-catch,要么 throws)。例如 IOException、SQLException、ClassNotFoundException;
- 非受查异常 / 运行时异常:即 RuntimeException 及其子类,编译器不强制处理。例如 NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException等。

JAVA中的异常处理方式
try-catch-finally
在 try 块中编写可能抛出异常的代码,使用一个或多个 catch 块捕获并处理特定类型的异常。finally 与 try 块配合,无论是否发生异常都会执行,用于释放资源(如关闭文件、数据库连接)。
java
public class TryCatchFinallyDemo {
public static void main(String[] args) {
System.out.println("--- 基本 try-catch-finally ---");
try {
int result = 10 / 0; // 抛出 ArithmeticException
System.out.println("结果: " + result);
} catch (ArithmeticException e) {
System.out.println("捕获异常: " + e.getMessage());
} finally {
System.out.println("finally 块总是执行");
}
}
}
throws
throws 声明抛出,在方法签名中声明该方法可能抛出的异常类型,将异常处理责任转交给调用者。
java
import java.io.*;
public class ThrowsDemo {
// 声明可能抛出 IOException
public static void readFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
System.out.println(br.readLine());
br.close();
}
public static void main(String[] args) {
try {
readFile("nonexistent.txt");
} catch (IOException e) {
System.out.println("调用者处理异常: " + e.getMessage());
}
}
}
throw
throw 手动抛出,在代码中主动创建并抛出一个异常对象(可以是 JDK 内置异常或自定义异常)。
java
public class ThrowDemo {
public static void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄必须在 0~150 之间");
}
System.out.println("年龄设置为: " + age);
}
public static void main(String[] args) {
setAge(25); // 正常
setAge(-5); // 抛出异常
}
}
自定义异常
对于自定义的异常,在声明时需要继承,继承Exception的为受查异常,继承RuntimeException的为非受查异常
java
// 自定义受检异常
class MyCheckedException extends Exception {
public MyCheckedException(String message) {
super(message);
}
}
// 自定义非受检异常
class MyUncheckedException extends RuntimeException {
public MyUncheckedException(String message) {
super(message);
}
}
public class CustomExceptionDemo {
public static void checkedMethod() throws MyCheckedException {
throw new MyCheckedException("这是一个受检异常");
}
public static void uncheckedMethod() {
throw new MyUncheckedException("这是一个非受检异常");
}
public static void main(String[] args) {
try {
checkedMethod();
} catch (MyCheckedException e) {
System.out.println(e.getMessage());
}
// 非受检异常可以不捕获(但会终止程序)
uncheckedMethod();
}
}
注意事项
避免在finally中使用return
尽量避免在finally中使用return,下面的程序中,程序先执行try中的代码,但最终还是会调用finally代码,从而将try中的代码进行了覆盖,最终返回20
java
public static int func(){
int a = 10;
try{
return a;
}catch (ArithmeticException e){
e.printStackTrace();
}finally {
return 20;
}
}
public static void main(String[] args) {
System.out.println(func());//20
}
受查异常 / 编译时异常不能单独使用 throw
如果一个方法内部可能抛出受查异常,那么该方法要么自己用 try-catch 捕获处理,要么在方法签名中用 throws 声明该异常。只用 throw 而不配合 throws 或 try-catch,编译会直接报错。
throw实际抛出一个异常对象,不满足编译器要求,它只是一个动作,没有处理也没有声明。
throw 必须与 throws 或 try-catch 配合
java
//方式1 配合 throws(声明抛出)
public void methodWithThrows() throws IOException {
throw new IOException(); // OK,因为方法声明了抛出 IOException
}
java
//方式2 配合 try-catch(捕获处理)
public void methodWithCatch() {
try {
throw new IOException(); // 被 catch 接住,不会向外抛
} catch (IOException e) {
System.out.println("处理了异常");
}
}
非受查异常 / 运行时异常可单独使用throw
对于 RuntimeException 及其子类(非受查异常),编译器不强制处理,所以可以单独使用 throw 而不加 throws 或 try-catch
java
public void runtimeEx() {
throw new NullPointerException(); // 编译通过,不需要 throws
}
Java 设计者希望通过编译时检查强制程序员处理受查异常,提高程序的健壮性。throw 只是抛出动作,并不包含任何"处理"语义。如果不强制配合 throws 或 try-catch,那么任何方法都可以随意抛出一个受查异常却不告知调用者,调用者也就无法预见和处理,受查异常就失去了意义。