18.1.4 Java异常处理机制与最佳实践
1. 异常体系结构
1.1 异常类层次结构
Throwable ├── Error (系统级错误,不应被捕获) │ ├── OutOfMemoryError │ ├── StackOverflowError │ └── VirtualMachineError └── Exception (程序级异常) ├── RuntimeException (运行时异常,非受检异常) │ ├── NullPointerException │ ├── IllegalArgumentException │ ├── IndexOutOfBoundsException │ └── ClassCastException └── 受检异常 (编译时必须处理) ├── IOException ├── SQLException └── ClassNotFoundException
1.2 异常分类详解
public class ExceptionClassificationDemo { // 1. Error示例 - 不应该被捕获 public void demonstrateError() { // StackOverflowError recursiveMethod(); // OutOfMemoryError List<byte[]> list = new ArrayList<>(); while (true) { list.add(new byte[1024 * 1024]); // 持续分配内存 } } private void recursiveMethod() { recursiveMethod(); // 无限递归 } // 2. 运行时异常示例 - 非受检异常 public void demonstrateRuntimeException() { // NullPointerException String str = null; int length = str.length(); // 运行时抛出NPE // IllegalArgumentException Thread.sleep(-1); // 非法参数 // IndexOutOfBoundsException List<String> list = new ArrayList<>(); String item = list.get(0); // 索引越界 // ClassCastException Object obj = "Hello"; Integer num = (Integer) obj; // 类型转换异常 } // 3. 受检异常示例 - 编译时必须处理 public void demonstrateCheckedException() throws IOException, SQLException { // IOException - 必须声明或捕获 FileReader file = new FileReader("nonexistent.txt"); // SQLException - 必须声明或捕获 Connection conn = DriverManager.getConnection("invalid_url"); // ClassNotFoundException - 必须声明或捕获 Class.forName("com.nonexistent.Class"); } }
2. 异常处理语法
2.1 try-catch-finally基本语法
public class BasicExceptionHandling { public void basicTryCatch() { try { // 可能抛出异常的代码 int result = 10 / 0; } catch (ArithmeticException e) { // 处理特定异常 System.out.println("除零异常: " + e.getMessage()); } catch (Exception e) { // 处理其他异常 System.out.println("其他异常: " + e.getMessage()); } finally { // 无论是否发生异常都会执行 System.out.println("清理资源"); } } // 多重catch的顺序很重要 public void multipleCatch() { try { String[] array = {"1", "2", "abc"}; for (String str : array) { int num = Integer.parseInt(str); System.out.println(10 / num); } } catch (NumberFormatException e) { // 具体异常要放在前面 System.out.println("数字格式异常: " + e.getMessage()); } catch (ArithmeticException e) { System.out.println("算术异常: " + e.getMessage()); } catch (Exception e) { // 通用异常放在最后 System.out.println("其他异常: " + e.getMessage()); } } }
2.2 try-with-resources语法
public class TryWithResourcesDemo { // JDK 7+ try-with-resources public void readFileWithTryWithResources() { try (FileReader file = new FileReader("data.txt"); BufferedReader reader = new BufferedReader(file)) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { System.out.println("文件读取异常: " + e.getMessage()); } // 资源会自动关闭,不需要finally块 } // 传统方式对比 public void readFileTraditional() { FileReader file = null; BufferedReader reader = null; try { file = new FileReader("data.txt"); reader = new BufferedReader(file); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { System.out.println("文件读取异常: " + e.getMessage()); } finally { // 手动关闭资源 try { if (reader != null) reader.close(); } catch (IOException e) { System.out.println("关闭reader失败"); } try { if (file != null) file.close(); } catch (IOException e) { System.out.println("关闭file失败"); } } } // 自定义资源类 public static class CustomResource implements AutoCloseable { private String name; public CustomResource(String name) { this.name = name; System.out.println("打开资源: " + name); } public void doSomething() { System.out.println("使用资源: " + name); } @Override public void close() { System.out.println("关闭资源: " + name); } } public void useCustomResource() { try (CustomResource resource = new CustomResource("数据库连接")) { resource.doSomething(); // 可能抛出异常 throw new RuntimeException("模拟异常"); } catch (Exception e) { System.out.println("捕获异常: " + e.getMessage()); } // 资源会自动关闭 } }
3. 异常抛出和声明
3.1 throw和throws的使用
public class ThrowAndThrowsDemo { // throws声明方法可能抛出的异常 public void readFile(String filename) throws IOException, FileNotFoundException { if (filename == null) { // throw主动抛出异常 throw new IllegalArgumentException("文件名不能为null"); } if (!new File(filename).exists()) { throw new FileNotFoundException("文件不存在: " + filename); } // 可能抛出IOException的代码 Files.readAllLines(Paths.get(filename)); } // 方法调用者必须处理受检异常 public void callReadFile() { try { readFile("data.txt"); } catch (FileNotFoundException e) { System.out.println("文件未找到: " + e.getMessage()); } catch (IOException e) { System.out.println("IO异常: " + e.getMessage()); } } // 或者继续向上抛出 public void callReadFileAndThrow() throws IOException { readFile("data.txt"); // 继续向上抛出 } }
3.2 异常链和异常包装
public class ExceptionChainingDemo { public void demonstrateExceptionChaining() { try { lowLevelMethod(); } catch (Exception e) { System.out.println("原始异常: " + e.getMessage()); System.out.println("异常链:"); Throwable cause = e; while (cause != null) { System.out.println(" " + cause.getClass().getSimpleName() + ": " + cause.getMessage()); cause = cause.getCause(); } } } private void lowLevelMethod() throws Exception { try { // 模拟底层异常 int result = 10 / 0; } catch (ArithmeticException e) { // 包装异常,保留原始异常信息 throw new Exception("业务处理失败", e); } } // 自定义异常包装 public class BusinessException extends Exception { public BusinessException(String message, Throwable cause) { super(message, cause); } } public void businessMethod() throws BusinessException { try { // 调用可能失败的底层方法 databaseOperation(); } catch (SQLException e) { // 包装为业务异常 throw new BusinessException("用户数据处理失败", e); } } private void databaseOperation() throws SQLException { throw new SQLException("数据库连接失败"); } }
4. 自定义异常
4.1 自定义异常类设计
// 自定义受检异常 public class UserNotFoundException extends Exception { private String userId; public UserNotFoundException(String userId) { super("用户不存在: " + userId); this.userId = userId; } public UserNotFoundException(String userId, Throwable cause) { super("用户不存在: " + userId, cause); this.userId = userId; } public String getUserId() { return userId; } } // 自定义运行时异常 public class InvalidConfigurationException extends RuntimeException { private String configKey; private String configValue; public InvalidConfigurationException(String configKey, String configValue) { super(String.format("无效配置 [%s=%s]", configKey, configValue)); this.configKey = configKey; this.configValue = configValue; } public InvalidConfigurationException(String configKey, String configValue, Throwable cause) { super(String.format("无效配置 [%s=%s]", configKey, configValue), cause); this.configKey = configKey; this.configValue = configValue; } public String getConfigKey() { return configKey; } public String getConfigValue() { return configValue; } } // 使用自定义异常 public class UserService { private Map<String, User> users = new HashMap<>(); public User findUser(String userId) throws UserNotFoundException { if (us
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经