4.6java异常处理
在 Java 中,异常(Exception)是指在程序执行过程中发生的不正常事件,它会中断程序的正常流程。Java 提供了一套完整的异常处理机制,帮助开发者更好地处理程序运行时出现的各种错误,增强程序的健壮性。
异常的分类
在 Java 中,异常类都继承自 java.lang.Throwable
类,Throwable
有两个直接子类:Error
和 Exception
。
1. Error
Error
类表示系统级的错误和资源耗尽错误,通常是由 JVM 或底层系统产生的,程序无法处理这些错误,也不应该尝试去捕获它们。例如,OutOfMemoryError
表示内存不足,StackOverflowError
表示栈溢出。
2. Exception
Exception
类表示程序可以捕获和处理的异常,它又可以分为两类:
- 受检查异常(Checked Exception):这类异常在编译时会被编译器检查,要求开发者必须进行处理(捕获或声明抛出)。常见的受检查异常包括
IOException
、SQLException
等。 - 非受检查异常(Unchecked Exception):也称为运行时异常(Runtime Exception),这类异常在编译时不会被编译器检查,通常是由程序逻辑错误引起的。常见的运行时异常包括
NullPointerException
、ArrayIndexOutOfBoundsException
、ArithmeticException
等。
层次结构图:
Throwable
├── Error
└── Exception├── RuntimeException(运行时异常)└── 其他受检异常(如 IOException)
异常处理机制
Java 提供了 try
、catch
、finally
和 throw
、throws
等关键字来实现异常处理。
1. try-catch
块
try-catch
块用于捕获和处理异常。try
块中包含可能会抛出异常的代码,catch
块用于捕获并处理相应的异常。
public class TryCatchExample {public static void main(String[] args) {try {int result = 10 / 0; // 会抛出 ArithmeticExceptionSystem.out.println(result);} catch (ArithmeticException e) {System.out.println("捕获到算术异常: " + e.getMessage());}}
}
多重捕获(Multi-catch)
Java 7+ 支持在一个 catch
块中捕获多个异常类型:
catch (IOException | SQLException e) { ... }
2. try-catch-finally
块
finally
块是可选的,无论 try
块中是否抛出异常,finally
块中的代码都会被执行。通常用于释放资源,如关闭文件、数据库连接等。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;public class TryCatchFinallyExample {public static void main(String[] args) {FileInputStream fis = null;try {fis = new FileInputStream("test.txt");// 读取文件的代码} catch (FileNotFoundException e) {System.out.println("文件未找到: " + e.getMessage());} finally {try {if (fis != null) {fis.close();}} catch (IOException e) {System.out.println("关闭文件时出错: " + e.getMessage());}}}
}
try-with-resources
自动关闭资源(Java 7+):
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {// 自动关闭流
}
3. throws
关键字
throws
关键字用于在方法声明中声明该方法可能会抛出的异常,调用该方法的代码必须处理这些异常。
import java.io.FileInputStream;
import java.io.FileNotFoundException;public class ThrowsExample {public static void readFile() throws FileNotFoundException {FileInputStream fis = new FileInputStream("test.txt");// 读取文件的代码}public static void main(String[] args) {try {readFile();} catch (FileNotFoundException e) {System.out.println("文件未找到: " + e.getMessage());}}
}
4. throw
关键字
throw
关键字用于手动抛出一个异常对象。
public class ThrowExample {public static void checkAge(int age) {if (age < 0) {throw new IllegalArgumentException("年龄不能为负数");}System.out.println("年龄合法: " + age);}public static void main(String[] args) {try {checkAge(-5);} catch (IllegalArgumentException e) {System.out.println("捕获到异常: " + e.getMessage());}}
}
自定义异常
在 Java 中,你可以通过继承 Exception
或 RuntimeException
类来创建自定义异常。
// 自定义受检查异常
class MyCheckedException extends Exception {public MyCheckedException(String message) {super(message);}
}// 自定义运行时异常
class MyRuntimeException extends RuntimeException {public MyRuntimeException(String message) {super(message);}
}public class CustomExceptionExample {public static void main(String[] args) {try {throw new MyCheckedException("这是一个自定义受检查异常");} catch (MyCheckedException e) {System.out.println("捕获到自定义受检查异常: " + e.getMessage());}try {throw new MyRuntimeException("这是一个自定义运行时异常");} catch (MyRuntimeException e) {System.out.println("捕获到自定义运行时异常: " + e.getMessage());}}
}
异常处理的最佳实践
- 捕获特定的异常:尽量捕获特定的异常,而不是捕获通用的
Exception
类,这样可以更精确地处理不同类型的异常。 - 避免空的
catch
块:空的catch
块会隐藏异常,导致调试困难,应该在catch
块中记录异常信息或进行相应的处理。 - 使用
finally
块释放资源:对于需要手动释放的资源,如文件、数据库连接等,应该在finally
块中进行释放。 - 合理使用
throws
和throw
:在方法中,如果无法处理某些异常,可以使用throws
关键字将异常抛给调用者;如果需要手动抛出异常,可以使用throw
关键字。