Java的异常
约 894 字大约 3 分钟
2025-07-14
在程序运行过程中,错误是不可避免的。为了保证程序的健壮性,必须处理各种各样的错误。
调用方法时获取失败的信息有两种方式:
返回错误码:通过返回特定的整数值来表示不同的错误类型。这种方式在底层 C 函数中比较常见,但处理起来比较麻烦。
异常处理机制:Java 内置了一套异常处理机制,使用异常来表示错误。异常是一种
class,可以在任何地方抛出,并在上层捕获。
1.1 异常的继承关系
Java 的异常体系根类是 Throwable,它继承自 Object。Throwable 分为两个主要分支:Error 和 Exception。
┌───────────┐
│ Object │
└───────────┘
▲
│
┌───────────┐
│ Throwable │
└───────────┘
▲
┌─────────┴─────────┐
│ │
┌───────────┐ ┌───────────┐
│ Error │ │ Exception │
└───────────┘ └───────────┘
▲ ▲
┌───────┘ ┌────┴──────────┐
│ │ │
┌─────────────────┐ ┌─────────────────┐┌───────────┐
│OutOfMemoryError │... │RuntimeException ││IOException│...
└─────────────────┘ └─────────────────┘└───────────┘
▲
┌───────────┴─────────────┐
│ │
┌─────────────────────┐ ┌─────────────────────────┐
│NullPointerException │ │IllegalArgumentException │...
└─────────────────────┘ └─────────────────────────┘- Error:表示严重的错误,程序通常无法处理,如
OutOfMemoryError(内存耗尽)、NoClassDefFoundError(无法加载某个 Class)、StackOverflowError(栈溢出)等。 - Exception:表示运行时的错误,可以被捕获并处理。
- 某些异常是应用程序逻辑的一部分,应该捕获并处理,如
NumberFormatException(数值类型的格式错误)、FileNotFoundException(未找到文件)、SocketException(读取网络失败)等。 - 还有一些异常是程序逻辑错误造成的,应该修复程序本身,如
NullPointerException(对null对象调用方法或字段)、IndexOutOfBoundsException(数组索引越界)等。
- 某些异常是应用程序逻辑的一部分,应该捕获并处理,如
1.2 Exception 的分类
Exception 分为两大类:
RuntimeException及其子类(例如:NullPointerException、IllegalArgumentException等)。- 非
RuntimeException(包括IOException、ReflectiveOperationException等),也称为 Checked Exception。
1.3 Java 的异常处理规则
- Checked Exception:必须捕获的异常,包括
Exception及其子类,但不包括RuntimeException及其子类。 - Unchecked Exception:不需要捕获的异常,包括
Error及其子类,RuntimeException及其子类。
需要注意的是,编译器对 RuntimeException 及其子类不做强制捕获要求,但应用程序本身不应该忽略 RuntimeException,是否需要捕获,需要具体问题具体分析。
1.4 捕获异常:try...catch 语句
使用 try...catch 语句捕获异常。将可能发生异常的代码放在 try{...} 块中,然后使用 catch 捕获对应的 Exception 及其子类。
try {
// 可能抛出异常的代码
} catch (ExceptionType1 e) {
// 处理 ExceptionType1 异常
} catch (ExceptionType2 e) {
// 处理 ExceptionType2 异常
} catch (Exception e) {
// 处理其他 Exception 异常
}下面是一个 try...catch 的例子:
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
try {
byte[] bs = toGBK("中文");
System.out.println(Arrays.toString(bs));
} catch (UnsupportedEncodingException e) {
System.out.println(e);
}
}
static byte[] toGBK(String s) throws UnsupportedEncodingException {
return s.getBytes("GBK");
}
}在 toGBK() 方法中,调用了 String.getBytes(String) 方法,该方法声明会抛出 UnsupportedEncodingException,因此必须捕获该异常或者在方法签名中用 throws 声明。
如果在方法定义处使用 throws Xxx 声明方法可能抛出的异常类型,那么调用方在调用该方法时,必须强制捕获这些异常,否则编译器会报错。所有未捕获的异常,最终必须在 main() 方法中捕获。
如果不想写任何 try 代码,可以直接把 main() 方法定义为 throws Exception,但这会导致一旦发生异常,程序会立刻退出。
1.5 避免“消化”异常
捕获异常后不进行任何处理是非常不好的做法,即使真的什么也做不了,也要先把异常记录下来。可以使用 printStackTrace() 方法打印异常栈信息,这是一个简单有用的快速打印异常的方法。
static byte[] toGBK(String s) {
try {
return s.getBytes("GBK");
} catch (UnsupportedEncodingException e) {
// 先记下来再说:
e.printStackTrace();
}
return null;
}