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;
}