`
一、学习异常的步骤
-
理解异常的基本概念
- 首先要明白异常是程序运行过程中出现的意外情况。可以通过实际生活中的例子来类比,比如开车在路上突然爆胎(类似于程序运行时出现异常),你需要有相应的处理措施来应对这种突发情况。在 Java 中,异常就是程序运行时的 “爆胎” 事件。
- 仔细研究 Java 中异常类的层次结构。Java 的异常类都继承自
java.lang.Throwable
类,它有两个重要的子类:Exception
(包括检查异常和运行时异常)和Error
。了解这个层次结构有助于你更好地理解不同类型异常的本质。 - 例如,
java.lang.Exception
是所有异常类的父类,java.io.IOException
(检查异常)和java.lang.NullPointerException
(运行时异常)都是它的子类
二 、学习异常类型
- 检查异常(Checked Exceptions)
- 深入了解常见的检查异常,如
FileNotFoundException
(文件不存在)、SQLException
(数据库操作异常)等。知道它们在什么情况下会被抛出,例如,当你使用FileInputStream
打开一个不存在的文件时,就会抛出FileNotFoundException
。 - 学习如何处理这些异常,主要是通过
try - catch
块或者在方法声明中使用throws
关键字来向上层抛出异常。
- 深入了解常见的检查异常,如
- 运行时异常(Runtime Exceptions)
- 掌握运行时异常的常见类型,像
NullPointerException
(空指针引用)、ArrayIndexOutOfBoundsException
(数组越界)和ArithmeticException
(算术异常,如除数为零)。 - 理解运行时异常通常是由代码逻辑错误引起的。例如,没有对可能为
null
的对象进行判空操作就直接调用其方法会导致NullPointerException
。
- 掌握运行时异常的常见类型,像
- 错误(Error)
- 学习
Error
类型的异常,如OutOfMemoryError
(内存不足)和StackOverflowError
(栈溢出)。要知道这些错误一般是由于系统资源耗尽或者程序的递归调用过深等严重问题导致的,并且通常很难从这些错误中恢复程序
- 学习
-
学习异常处理机制
- try - catch 块
- 理解
try
块是包裹可能抛出异常的代码区域。在try
块中放入可能出现问题的代码,如文件读取、网络连接等操作。 - 学习如何编写
catch
块来捕获特定类型的异常。catch
块中的参数是异常对象,通过这个对象可以获取异常的相关信息,如异常消息(getMessage()
方法)和堆栈跟踪(printStackTrace()
方法)。 - 例如,下面的代码展示了如何捕获
FileNotFoundException
并打印异常信息:
- 理解
- try - catch 块
java
try {
File file = new File("nonexistent.txt");
FileReader reader = new FileReader(file);
} catch (FileNotFoundException e) {
System.out.println("文件不存在:" + e.getMessage());
}
- finally 块
- 明白
finally
块的作用是无论try
块中是否抛出异常,其中的代码都会被执行。它常用于释放资源,比如关闭文件流、数据库连接等。 - 例如,在下面的代码中,
finally
块确保文件流被关闭:
- 明白
FileReader reader = null;
try {
File file = new File("example.txt");
reader = new FileReader(file);
// 读取文件操作
} catch (FileNotFoundException e) {
System.out.println("文件未找到异常:" + e.getMessage());
} finally {
if (reader!= null) {
try {
reader.close();
} catch (IOException e) {
System.out.println("关闭文件流异常:" + e.getMessage());
}
}
}
- 抛出异常(throw 和 throws)
- 学会在方法内部使用
throw
关键字手动抛出异常。这通常用于当方法执行过程中遇到不符合业务逻辑的情况时,主动抛出异常来通知调用者。 - 例如,下面的方法检查年龄是否为负数,如果是则抛出异常:
- 学会在方法内部使用
java
public void checkAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
} else {
System.out.println("年龄合法");
}
}
- 理解
throws
关键字在方法声明中的作用。它用于声明该方法可能会抛出的异常类型,让调用者知道需要处理这些潜在的异常。 - 例如,下面的方法声明了可能抛出
FileNotFoundException
:
java
public void readFile(String fileName) throws FileNotFoundException {
File file = new File(fileName);
FileReader reader = new FileReader(file);
// 读取文件操作
}
- 适当的异常处理策略
- 在编写代码时,对于检查异常,要根据实际情况决定是在当前方法中使用
try - catch
块处理,还是将异常向上层方法抛出(使用throws
关键字)。如果当前方法有足够的信息来处理异常并且能够恢复程序的正常执行,那么就使用try - catch
块。否则,向上层抛出异常,让更合适的层次来处理。 - 对于运行时异常,虽然编译器不强制要求处理,但最好还是在可能出现运行时异常的地方添加适当的
try - catch
块来提高程序的健壮性。例如,在访问对象的属性或方法之前,先进行null
检查,以避免NullPointerException
。 - 例如,在一个方法中访问一个可能为
null
的对象的方法时:
- 在编写代码时,对于检查异常,要根据实际情况决定是在当前方法中使用
java
public void process(Object obj) {
if (obj!= null) {
try {
obj.someMethod();
} catch (NullPointerException e) {
System.out.println("对象为空,无法执行方法:" + e.getMessage());
}
} else {
System.out.println("对象为null");
}
}
- 提供有意义的异常信息
- 当抛出异常时,要提供清晰、准确的异常信息。这样有助于调试和定位问题。可以在异常消息中包含一些关键的信息,比如在自定义异常中:
java
public class MyCustomException extends Exception {
public MyCustomException(String message) {
super(message);
}
}
- 然后在抛出这个异常时,提供有用的信息:
java
public void someMethod() throws MyCustomException {
int value = getSomeValue();
if (value < 0) {
throw new MyCustomException("获取的值为负数,不符合要求:" + value);
}
}
- 避免过度使用异常
- 不要将异常作为控制程序流程的常规手段。异常处理是有性能开销的,过度使用会导致程序性能下降。例如,不要使用异常来处理可以通过简单的条件判断就能解决的情况。
- 比如,检查一个整数是否在某个范围内,不应该这样做:
java
public void checkValue(int value) {
try {
if (value < 0 || value > 100) {
throw new RuntimeException("值不在0 - 100范围内");
}
} catch (RuntimeException e) {
System.out.println("异常:" + e.getMessage());
}
}
- 而应该使用正常的条件判断:
java
public void checkValue(int value) {
if (value < 0 || value > 100) {
System.out.println("值不在0 - 100范围内");
}
}