Java异常处理全解析:从基础到高级实战

掌握Java语法解析:从基础到高级实战 摘要:本文系统介绍了Java语法解析的核心技术与应用实践。内容涵盖基础解析流程(词法分析、语法分析、语义分析)、常用工具(ANTLR、JavaParser)的深度应用,以及解析算法实现和优化技术。重点探讨了解析器在代码格式化、静态分析、IDE功能等场景的实际应用,并提供了递归下降法等自定义解析器的进阶实现方案。文中还详细分析了复杂语言特性的处理方法、错误恢复最佳实践以及工具集成考量,为构建高效Java解析解决方案提供了全面指导。 阅读详情

一、为什么需要异常处理?

1.1 问题的引出

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println(6 / 0);  // 这里会抛出ArithmeticException
        System.out.println("---------------");  // 这行代码永远不会执行
    }
}

运行结果:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:3)

1.2 异常处理的重要性

  1. 程序健壮性:让程序在遇到错误时不会崩溃

  2. 用户体验:给用户友好的错误提示,而不是一堆红色错误信息

  3. 代码可维护性:清晰的异常处理逻辑,便于调试和维护

  4. 资源管理:确保异常发生时也能正确释放资源

1.3 没有异常处理的世界

// 场景1:文件操作
public void readFile() {
    File file = new File("test.txt");
    // 如果没有异常处理,每次调用都要检查返回值
    if (file.exists()) {
        // 读取文件...
    } else {
        System.out.println("文件不存在");
    }
}

// 场景2:网络请求
public void requestData() {
    // 需要检查网络连接、服务器状态、数据格式等
    // 代码会变得冗长且难以维护
}

二、Java异常体系结构

2.1 异常类层次结构

Throwable (可抛出的)
    |
    ├── Error (错误) ← 程序无法处理的严重问题
    │    ├── VirtualMachineError (虚拟机错误)
    │    ├── OutOfMemoryError (内存溢出)
    │    └── StackOverflowError (栈溢出)
    │
    └── Exception (异常) ← 程序可以处理的
         │
         ├── 编译时异常 (Checked Exception)
         │    ├── IOException
         │    │    └── FileNotFoundException
         │    ├── SQLException
         │    ├── ClassNotFoundException
         │    └── CloneNotSupportedException
         │
         └── 运行时异常 (Unchecked Exception / RuntimeException)
              ├── NullPointerException
              ├── ArrayIndexOutOfBoundsException
              ├── ArithmeticException
              ├── ClassCastException
              ├── IllegalArgumentException
              │    └── NumberFormatException
              └── IllegalStateException

2.2 Error vs Exception

特性

Error

Exception

严重程度​

严重,程序无法恢复

可恢复,程序可以处理

处理方式​

不应被捕获处理

应该被捕获处理

示例​

OutOfMemoryError, StackOverflowError

IOException, NullPointerException

来源​

JVM或系统底层

应用程序代码

2.3 编译时异常 vs 运行时异常

特性

编译时异常 (Checked Exception)

运行时异常 (Unchecked Exception)

检查时机​

编译时检查

运行时检查

处理要求​

必须处理(try-catch或throws)

不强制处理

继承关系​

Exception直接子类

RuntimeException子类

设计理念​

可预期的异常

编程错误

示例​

IOException, SQLException

NullPointerException, IndexOutOfBoundsException

2.4 常见异常详解

1. NullPointerException(空指针异常)
public class NullPointerDemo {
    public static void main(String[] args) {
        String str = null;
        
        // 情况1:调用null对象的方法
        // System.out.println(str.length());  // 抛出NullPointerException
        
        // 情况2:访问null对象的属性
        // System.out.println(str.toString());  // 抛出NullPointerException
        
        // 解决方案:判空
        if (str != null) {
            System.out.println(str.length());
        } else {
            System.out.println("字符串为null");
        }
        
        // Java 8+ 的Optional方案
        String result = Optional.ofNullable(str)
                                .map(String::length)
                                .map(len -> "长度:" + len)
                                .orElse("字符串为null");
        System.out.println(result);
    }
}
2. ArrayIndexOutOfBoundsException(数组下标越界)
public class ArrayIndexDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};
        
        // 错误:访问不存在的索引
        // System.out.println(arr[5]);  // 索引范围是0-4
        
        // 正确:检查索引边界
        int index = 5;
        if (index >= 0 && index < arr.length) {
            System.out.println(arr[index]);
        } else {
            System.out.println("索引越界:" + index);
        }
    }
}
3. ArithmeticException(算术异常)
public class ArithmeticDemo {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        
        // 错误:除数为0
        // System.out.println(a / b);  // 抛出ArithmeticException
        
        // 解决方案:检查除数
        if (b != 0) {
            System.out.println(a / b);
        } else {
            System.out.println("除数不能为0");
        }
        
        // 浮点数除0的特殊情况
        double x = 10.0;
        double y = 0.0;
        System.out.println(x / y);  // Infinity
        System.out.println(-x / y); // -Infinity
        System.out.println(0.0 / 0.0);  // NaN
    }
}
4. ClassCastException(类型转换异常)
public class ClassCastDemo {
    public static void main(String[] args) {
        Object obj = "Hello";
        
        // 错误:不安全的类型转换
        // Integer num = (Integer) obj;  // 抛出ClassCastException
        
        // 解决方案1:使用instanceof检查
        if (obj instanceof Integer) {
            Integer num = (Integer) obj;
            System.out.println(num);
        } else {
            System.out.println("obj不是Integer类型");
        }
        
        // 解决方案2:使用泛型
        List<String> list = new ArrayList<>();
        // 编译时检查,避免运行时异常
    }
}
5. NumberFormatException(数字格式异常)
public class NumberFormatDemo {
    public static void main(String[] args) {
        String str1 = "123";
        String str2 = "abc";
        
        // 正确转换
        int num1 = Integer.parseInt(str1);
        System.out.println("转换结果:" + num1);
        
        // 错误转换
        // int num2 = Integer.parseInt(str2);  // 抛出NumberFormatException
        
        // 解决方案:异常处理
        try {
            int num2 = Integer.parseInt(str2);
            System.out.println("转换结果:" + num2);
        } catch (NumberFormatException e) {
            System.out.println("数字格式错误:" + str2);
        }
        
        // 正则表达式验证
        if (str2.matches("-?\\d+")) {
            int num3 = Integer.parseInt(str2);
            System.out.println("转换结果:" + num3);
        } else {
            System.out.println("不是有效的数字:" + str2);
        }
    }
}
6. FileNotFoundException(文件未找到异常)
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class FileNotFoundDemo {
    public static void main(String[] args) {
        File file = new File("不存在的文件.txt");
        
        try (Scanner scanner = new Scanner(file)) {
            while (scanner.hasNextLine()) {
                System.out.println(scanner.nextLine());
            }
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在:" + file.getAbsolutePath());
            // 可以创建新文件或提示用户
        }
    }
}

三、异常处理的三种方式

3.1 try-catch-finally 结构

基本语法
try {
    // 可能抛出异常的代码
    // 1. 文件操作
    // 2. 网络请求
    // 3. 数据库操作
    // 4. 用户输入处理
} catch (异常类型1 变量名1) {
    // 处理异常类型1
} catch (异常类型2 变量名2) {
    // 处理异常类型2
} finally {
    // 无论是否发生异常,都会执行的代码
    // 通常用于资源释放
}
完整示例
import java.io.*;

public class TryCatchDemo {
    public static void readFile(String filePath) {
        FileReader reader = null;
        BufferedReader bufferedReader = null;
        
        try {
            // 1. 打开文件
            reader = new FileReader(filePath);
            bufferedReader = new BufferedReader(reader);
            
            // 2. 读取文件
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
            
        } catch (FileNotFoundException e) {
            // 文件不存在异常
            System.err.println("文件未找到:" + e.getMessage());
            
        } catch (IOException e) {
            // IO异常
            System.err.println("读取文件出错:" + e.getMessage());
            
        } catch (Exception e) {
            // 其他所有异常
            System.err.println("发生未知错误:" + e.getMessage());
            
        } finally {
            // 3. 释放资源
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                System.err.println("关闭文件时出错:" + e.getMessage());
            }
        }
    }
}
try-with-resources(Java 7+)
public class TryWithResourcesDemo {
    public static void readFile(String filePath) {
        // 自动关闭资源(实现了AutoCloseable接口)
        try (FileReader reader = new FileReader(filePath);
             BufferedReader bufferedReader = new BufferedReader(reader)) {
            
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
            
        } catch (FileNotFoundException e) {
            System.err.println("文件未找到:" + e.getMessage());
            
        } catch (IOException e) {
            System.err.println("读取文件出错:" + e.getMessage());
            
        }  // finally块不再需要,资源会自动关闭
    }
}

3.2 throws 声明异常

方法声明异常
import java.io.*;

public class ThrowsDemo {
    
    // 方法声明可能抛出的异常
    public void processFile(String filePath) 
            throws FileNotFoundException, IOException {
        
        // 不在这里处理异常,让调用者处理
        try (BufferedReader reader = new BufferedReader(
                new FileReader(filePath))) {
            
            String line;
            while ((line = reader.readLine()) != null) {
                processLine(line);  // 可能抛出其他异常
            }
        }
    }
    
    private void processLine(String line) throws IOException {
        if (line == null || line.isEmpty()) {
            throw new IOException("空行");
        }
        // 处理逻辑...
    }
    
    public static void main(String[] args) {
        ThrowsDemo demo = new ThrowsDemo();
        
        try {
            demo.processFile("data.txt");
        } catch (FileNotFoundException e) {
            System.err.println("文件不存在:" + e.getMessage());
        } catch (IOException e) {
            System.err.println("IO错误:" + e.getMessage());
        }
    }
}
方法调用链中的异常传递
public class ExceptionPropagation {
    
    public void methodA() throws IOException {
        methodB();  // 向上传播异常
    }
    
    public void methodB() throws IOException {
        methodC();  // 向上传播异常
    }
    
    public void methodC() throws IOException {
        // 可能抛出IOException
        throw new IOException("methodC异常");
    }
    
    public static void main(String[] args) {
        ExceptionPropagation ep = new ExceptionPropagation();
        
        try {
            ep.methodA();
        } catch (IOException e) {
            // 打印完整的调用栈
            e.printStackTrace();
            
            // 获取异常信息
            System.out.println("异常信息:" + e.getMessage());
            System.out.println("异常类型:" + e.getClass().getName());
            
            // 获取根本原因
            Throwable cause = e.getCause();
            if (cause != null) {
                System.out.println("根本原因:" + cause.getMessage());
            }
        }
    }
}

3.3 throw 抛出异常

手动抛出异常
public class ThrowDemo {
    
    public static double divide(double a, double b) {
        if (b == 0) {
            // 手动抛出异常
            throw new ArithmeticException("除数不能为0");
        }
        return a / b;
    }
    
    public static void validateAge(int age) {
        if (age < 0) {
            throw new IllegalArgumentException("年龄不能为负数:" + age);
        }
        if (age > 150) {
            throw new IllegalArgumentException("年龄不合法:" + age);
        }
        System.out.println("年龄验证通过:" + age);
    }
    
    public static void main(String[] args) {
        // 示例1:除数为0
        try {
            double result = divide(10, 0);
            System.out.println("结果:" + result);
        } catch (ArithmeticException e) {
            System.out.println("捕获到异常:" + e.getMessage());
        }
        
        // 示例2:参数验证
        try {
            validateAge(-5);
        } catch (IllegalArgumentException e) {
            System.out.println("参数错误:" + e.getMessage());
        }
        
        // 示例3:重新抛出异常
        try {
            validateAge(200);
        } catch (IllegalArgumentException e) {
            System.err.println("原始异常:" + e.getMessage());
            // 包装后重新抛出
            throw new RuntimeException("验证失败", e);
        }
    }
}

四、finally 块的深入理解

4.1 finally 的执行时机

public class FinallyDemo {
    
    public static int test1() {
        try {
            System.out.println("try块执行");
            return 1;  // 这里会记录返回值1
        } catch (Exception e) {
            return 2;
        } finally {
            System.out.println("finally块执行");
            // 注意:finally中的return会覆盖try中的return
        }
    }
    
    public static int test2() {
        int i = 0;
        try {
            i = 10;
            return i;  // 记录返回值10
        } finally {
            i = 20;     // 虽然修改了i,但不影响返回值
            System.out.println("finally中i=" + i);
        }
    }
    
    public static int test3() {
        try {
            return 1;
        } finally {
            return 2;  // finally中的return会覆盖try中的return
        }
    }
    
    public static void main(String[] args) {
        System.out.println("test1结果:" + test1());
        // 输出:
        // try块执行
        // finally块执行
        // test1结果:1
        
        System.out.println("test2结果:" + test2());
        // 输出:
        // finally中i=20
        // test2结果:10
        
        System.out.println("test3结果:" + test3());
        // 输出:test3结果:2
    }
}

4.2 finally 在资源管理中的应用

public class ResourceManagement {
    
    // 传统方式
    public void processFileOld(String filePath) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(filePath);
            // 处理文件...
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    // try-with-resources方式
    public void processFileNew(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath);
             BufferedInputStream bis = new BufferedInputStream(fis)) {
            // 处理文件...
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 不需要finally块,资源会自动关闭
    }
    
    // 自定义资源
    static class MyResource implements AutoCloseable {
        public void doSomething() {
            System.out.println("MyResource正在工作...");
        }
        
        @Override
        public void close() {
            System.out.println("MyResource被关闭");
        }
    }
    
    public static void main(String[] args) {
        // 使用自定义资源
        try (MyResource resource = new MyResource()) {
            resource.doSomething();
        }  // 自动调用close()
    }
}

五、异常处理的最佳实践

5.1 异常处理原则

原则1:具体异常优于通用异常
// 不推荐
try {
    // 业务代码
} catch (Exception e) {  // 太宽泛
    e.printStackTrace();
}

// 推荐
try {
    // 业务代码
} catch (FileNotFoundException e) {
    // 处理文件不存在
    System.err.println("文件不存在:" + e.getMessage());
} catch (IOException e) {
    // 处理IO异常
    System.err.println("IO错误:" + e.getMessage());
} catch (Exception e) {
    // 最后捕获通用异常
    System.err.println("未知错误:" + e.getMessage());
    throw e;  // 重新抛出
}
原则2:不要忽略异常
// 不推荐:异常被静默忽略
try {
    process();
} catch (Exception e) {
    // 什么也不做
}

// 推荐做法1:记录日志
try {
    process();
} catch (Exception e) {
    log.error("处理失败", e);
}

// 推荐做法2:包装后重新抛出
try {
    process();
} catch (Exception e) {
    throw new BusinessException("处理失败", e);
}

// 推荐做法3:恢复或降级
try {
    process();
} catch (Exception e) {
    fallbackProcess();  // 降级处理
}
原则3:不要用异常控制流程
// 不推荐:用异常控制流程
public int findIndex(String[] array, String target) {
    for (int i = 0; i < array.length; i++) {
        try {
            if (array[i].equals(target)) {
                return i;
            }
        } catch (NullPointerException e) {
            // 跳过null
        }
    }
    return -1;
}

// 推荐:正常控制流程
public int findIndexBetter(String[] array, String target) {
    for (int i = 0; i < array.length; i++) {
        if (array[i] != null && array[i].equals(target)) {
            return i;
        }
    }
    return -1;
}
原则4:在合适的层级处理异常
// 三层架构中的异常处理
public class UserService {
    
    // 数据访问层
    public class UserDao {
        public User findById(int id) throws SQLException {
            // 数据库操作,抛出SQLException
        }
    }
    
    // 业务逻辑层
    public class UserService {
        private UserDao userDao = new UserDao();
        
        public User getUserById(int id) throws BusinessException {
            try {
                return userDao.findById(id);
            } catch (SQLException e) {
                // 转换异常类型
                throw new BusinessException("查询用户失败", e);
            }
        }
    }
    
    // 表现层
    public class UserController {
        private UserService userService = new UserService();
        
        public void showUser(int id) {
            try {
                User user = userService.getUserById(id);
                // 显示用户信息
            } catch (BusinessException e) {
                // 给用户友好提示
                showErrorMessage("获取用户信息失败");
            }
        }
    }
}

5.2 异常链(Chained Exceptions)

public class ExceptionChain {
    
    public static void processData() throws DataProcessException {
        try {
            readDataFromFile();
        } catch (IOException e) {
            // 包装原始异常,形成异常链
            throw new DataProcessException("数据处理失败", e);
        }
    }
    
    private static void readDataFromFile() throws IOException {
        throw new IOException("文件读取失败");
    }
    
    static class DataProcessException extends Exception {
        public DataProcessException(String message, Throwable cause) {
            super(message, cause);
        }
    }
    
    public static void main(String[] args) {
        try {
            processData();
        } catch (DataProcessException e) {
            // 打印完整异常链
            e.printStackTrace();
            
            // 遍历异常链
            Throwable current = e;
            while (current != null) {
                System.out.println("异常: " + current.getClass().getName());
                System.out.println("信息: " + current.getMessage());
                current = current.getCause();
            }
        }
    }
}

六、自定义异常

6.1 为什么需要自定义异常?

  1. 业务语义:更准确地描述业务问题

  2. 异常分类:便于按类型处理不同异常

  3. 信息丰富:携带更多业务相关信息

  4. 统一处理:便于统一异常处理逻辑

6.2 创建自定义异常

// 1. 检查异常(Checked Exception)
public class BusinessException extends Exception {
    
    // 错误码
    private String errorCode;
    
    // 错误信息
    private String errorMessage;
    
    // 构造方法
    public BusinessException(String errorCode, String errorMessage) {
        super(errorCode + ": " + errorMessage);
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }
    
    public BusinessException(String errorCode, String errorMessage, Throwable cause) {
        super(errorCode + ": " + errorMessage, cause);
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }
    
    // Getter方法
    public String getErrorCode() {
        return errorCode;
    }
    
    public String getErrorMessage() {
        return errorMessage;
    }
}

// 2. 运行时异常(Unchecked Exception)
public class BusinessRuntimeException extends RuntimeException {
    
    private String errorCode;
    private String errorMessage;
    
    public BusinessRuntimeException(String errorCode, String errorMessage) {
        super(errorCode + ": " + errorMessage);
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }
    
    public BusinessRuntimeException(String errorCode, String errorMessage, Throwable cause) {
        super(errorCode + ": " + errorMessage, cause);
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }
    
    // Getter方法
    public String getErrorCode() {
        return errorCode;
    }
    
    public String getErrorMessage() {
        return errorMessage;
    }
}

6.3 使用自定义异常

public class UserService {
    
    // 错误码定义
    public interface ErrorCode {
        String USER_NOT_FOUND = "USER_001";
        String USER_INVALID = "USER_002";
        String USER_EXISTS = "USER_003";
    }
    
    public User findUserById(int userId) throws BusinessException {
        if (userId <= 0) {
            throw new BusinessException(
                ErrorCode.USER_INVALID, 
                "用户ID不合法: " + userId
            );
        }
        
        User user = userDao.findById(userId);
        if (user == null) {
            throw new BusinessException(
                ErrorCode.USER_NOT_FOUND,
                "用户不存在: " + userId
            );
        }
        
        return user;
    }
    
    public void registerUser(User user) {
        if (userDao.exists(user.getUsername())) {
            throw new BusinessRuntimeException(
                ErrorCode.USER_EXISTS,
                "用户已存在: " + user.getUsername()
            );
        }
        userDao.save(user);
    }
    
    public static void main(String[] args) {
        UserService service = new UserService();
        
        try {
            // 测试检查异常
            User user = service.findUserById(-1);
        } catch (BusinessException e) {
            System.out.println("错误码: " + e.getErrorCode());
            System.out.println("错误信息: " + e.getErrorMessage());
            // 根据错误码做不同处理
            switch (e.getErrorCode()) {
                case ErrorCode.USER_NOT_FOUND:
                    // 显示用户不存在提示
                    break;
                case ErrorCode.USER_INVALID:
                    // 显示参数错误提示
                    break;
            }
        }
        
        // 测试运行时异常
        try {
            service.registerUser(new User("admin"));
        } catch (BusinessRuntimeException e) {
            System.out.println("运行时异常: " + e.getMessage());
        }
    }
}

6.4 自定义异常的最佳实践

// 1. 定义异常基类
public abstract class BaseException extends RuntimeException {
    private final ErrorCode errorCode;
    private final Object data;
    
    public BaseException(ErrorCode errorCode, String message, Object data) {
        super(message);
        this.errorCode = errorCode;
        this.data = data;
    }
    
    public BaseException(ErrorCode errorCode, String message, Throwable cause, Object data) {
        super(message, cause);
        this.errorCode = errorCode;
        this.data = data;
    }
    
    public ErrorCode getErrorCode() {
        return errorCode;
    }
    
    public Object getData() {
        return data;
    }
}

// 2. 定义具体业务异常
public class UserNotFoundException extends BaseException {
    public UserNotFoundException(Long userId) {
        super(ErrorCode.USER_NOT_FOUND, 
              "用户不存在: " + userId, 
              Map.of("userId", userId));
    }
}

public class InsufficientBalanceException extends BaseException {
    public InsufficientBalanceException(BigDecimal balance, BigDecimal required) {
        super(ErrorCode.INSUFFICIENT_BALANCE,
              "余额不足: 当前余额" + balance + ",需要" + required,
              Map.of("balance", balance, "required", required));
    }
}

// 3. 统一异常处理器
@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(BaseException.class)
    public ResponseEntity<ErrorResponse> handleBaseException(BaseException e) {
        ErrorResponse response = new ErrorResponse(
            e.getErrorCode().getCode(),
            e.getMessage(),
            e.getData()
        );
        return ResponseEntity.status(e.getErrorCode().getHttpStatus())
                             .body(response);
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception e) {
        ErrorResponse response = new ErrorResponse(
            "SYSTEM_ERROR",
            "系统内部错误",
            null
        );
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                             .body(response);
    }
}

七、异常处理的设计模式

7.1 异常转换模式

// 将底层异常转换为业务异常
public class UserRepository {
    public User findById(int id) {
        try {
            return jdbcTemplate.queryForObject(
                "SELECT * FROM users WHERE id = ?", 
                new UserRowMapper(), 
                id
            );
        } catch (EmptyResultDataAccessException e) {
            throw new UserNotFoundException(id);
        } catch (DataAccessException e) {
            throw new DatabaseException("查询用户失败", e);
        }
    }
}

7.2 重试模式

public class RetryTemplate {
    
    public <T> T executeWithRetry(Callable<T> task, int maxRetries) {
        int retryCount = 0;
        while (true) {
            try {
                return task.call();
            } catch (Exception e) {
                retryCount++;
                if (retryCount >= maxRetries) {
                    throw new RetryExhaustedException("重试次数耗尽", e);
                }
                
                // 指数退避
                long waitTime = (long) Math.pow(2, retryCount) * 1000;
                try {
                    Thread.sleep(waitTime);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("重试被中断", ie);
                }
                
                System.out.println("重试第" + retryCount + "次,等待" + waitTime + "ms");
            }
        }
    }
}

7.3 熔断器模式

public class CircuitBreaker {
    
    private enum State { CLOSED, OPEN, HALF_OPEN }
    
    private State state = State.CLOSED;
    private int failureCount = 0;
    private final int failureThreshold = 5;
    private final long timeout = 30000; // 30秒
    private long lastFailureTime = 0;
    
    public <T> T execute(Supplier<T> supplier) {
        if (state == State.OPEN) {
            if (System.currentTimeMillis() - lastFailureTime > timeout) {
                state = State.HALF_OPEN;
            } else {
                throw new CircuitBreakerOpenException("熔断器已打开");
            }
        }
        
        try {
            T result = supplier.get();
            if (state == State.HALF_OPEN) {
                state = State.CLOSED;
                failureCount = 0;
            }
            return result;
            
        } catch (Exception e) {
            failureCount++;
            if (state == State.HALF_OPEN || failureCount >= failureThreshold) {
                state = State.OPEN;
                lastFailureTime = System.currentTimeMillis();
            }
            throw e;
        }
    }
}

八、实际应用场景总结

8.1 何时使用try-catch?

// 场景1:需要继续执行的业务逻辑
public void processOrder(Order order) {
    try {
        // 主要业务逻辑
        validateOrder(order);
        processPayment(order);
        updateInventory(order);
        
    } catch (PaymentException e) {
        // 支付失败,记录日志并继续处理其他订单
        log.error("订单支付失败: {}", order.getId(), e);
        notifyUserPaymentFailed(order.getUserId());
        
    } catch (InventoryException e) {
        // 库存不足,记录日志
        log.error("库存不足: {}", order.getProductId(), e);
        notifyUserOutOfStock(order.getUserId());
        
    } finally {
        // 无论成功失败,都需要执行
        updateOrderStatus(order);
    }
}

8.2 何时使用throws?

// 场景1:框架或库的设计
public class FileProcessor {
    /**
     * 处理文件
     * @param filePath 文件路径
     * @throws FileNotFoundException 文件不存在
     * @throws IOException 读取错误
     */
    public void process(String filePath) throws FileNotFoundException, IOException {
        // 让调用者决定如何处理异常
    }
}

// 场景2:中间层传递异常
public class ServiceLayer {
    public User getUser(int id) throws BusinessException {
        try {
            return dao.findById(id);
        } catch (SQLException e) {
            // 转换并向上传递
            throw new BusinessException("查询失败", e);
        }
    }
}

8.3 何时使用throw?

// 场景1:参数验证
public void setAge(int age) {
    if (age < 0 || age > 150) {
        throw new IllegalArgumentException("年龄必须在0-150之间: " + age);
    }
    this.age = age;
}

// 场景2:业务规则检查
public void transfer(Account from, Account to, BigDecimal amount) {
    if (from.getBalance().compareTo(amount) < 0) {
        throw new InsufficientBalanceException(
            from.getBalance(),
            amount
        );
    }
    // 执行转账...
}

// 场景3:快速失败
public void initialize() {
    if (initialized) {
        throw new IllegalStateException("已经初始化过");
    }
    // 初始化逻辑...
    initialized = true;
}

九、常见面试题

9.1 基础问题

  1. Error和Exception有什么区别?

  2. 运行时异常和编译时异常有什么区别?

  3. finally块一定会执行吗?

  4. try、catch、finally的执行顺序是怎样的?

9.2 进阶问题

  1. try-with-resources是如何工作的?

  2. 异常链是什么?有什么作用?

  3. 如何自定义异常?应该继承哪个类?

  4. 什么时候应该抛出异常,什么时候应该捕获异常?

9.3 实践问题

  1. 下面的代码有什么问题?如何改进?

    try {
        // 业务代码
    } catch (Exception e) {
        // 空catch块
    }
  2. finally块中的return会覆盖try块中的return吗?

  3. 什么是异常屏蔽(Suppressed Exceptions)?


总结

异常处理是Java编程中非常重要的部分,良好的异常处理能够:

  1. 提高程序的健壮性和可靠性

  2. 提供更好的用户体验

  3. 便于调试和维护

  4. 保证资源的正确释放

记住以下关键点:

  • 区分检查异常和运行时异常

  • 不要忽略异常

  • 在合适的层级处理异常

  • 使用具体的异常类型

  • 为异常提供有用的上下文信息

  • 考虑使用自定义异常表达业务含义

  • 使用try-with-resources管理资源

通过合理使用异常处理机制,你可以编写出更加健壮、可维护的Java应用程序。

56、Java编程全解析:从基础到高级应用 本博客全面解析Java编程,从基础语法到高级应用,涵盖类与对象、异常处理、集合框架、线程与并发、输入输出操作、JUnit测试、注解、泛型、设计模式、国际化与本地化以及常用工具和框架等内容。通过丰富的代码示例和详细讲解,帮助开发者系统掌握Java核心知识,并提升实际开发能力。 阅读详情

相关推荐

Java全栈编程实战训练营:从基础到高级技能全覆盖

尽管Java标准库提供了丰富的异常类型,但在复杂业务系统中,往往需要定义更具语义化的异常来准确描述特定场景下的错误。自定义异常不仅可以提高代码可读性,还能帮助团队快速定位问题根源。创建自定义异常类非常简单:只需继承Exception(用于受检异常)或(用于非受检异常),并提供合适的构造函数即可。以下是一个电商系统中订单处理相关的自定义异常示例:// 受检异常:订单支付失败// Getter 方法省略...// 非受检异常:库存不足。

weixin_42518334的博客 960

Java编程全解析:从基础到高级应用

本文系统介绍Java核心技术,涵盖基础语法、面向对象编程、异常处理、集合框架和输入输出流五大模块。通过理论讲解与代码示例相结合的方式,详细解析变量声明、类与对象、异常捕获、集合操作以及文件读写等核心知识点,帮助开发者掌握Java编程基础,解决常见问题如数据类型转换错误、数组越界异常、集合性能优化等。适合Java入门1-3年的开发者系统学习,提升编程能力与代码质量。

fykam的博客 1618

全面解析Java编程:从基础到高级概念

Java作为一门广泛使用的编程语言,在软件开发领域占有举足轻重的地位。自1995年由Sun Microsystems公司发布以来,Java凭借其“编写一次,到处运行”的跨平台特性,迅速成为企业级应用开发的首选语言。本章将带领读者初步了解Java语言的基本概念、历史背景和发展前景,为后续章节的学习打下坚实的基础。在Java编程语言中,类(Class)是面向对象编程的基础。它是一种定义对象属性和行为的模板或蓝图。类可以包含字段(Field)来存储数据,方法(Method)来描述行为,以及嵌套类和内部类。

weixin_42601608的博客 1012

Java异常处理全解析:从基础到高级

本文全面解析Java异常处理机制,从基础概念到高级应用。首先介绍异常的本质是程序运行中的意外事件,Java异常体系以Throwable为根类分为Error和Exception两大类。详细讲解异常传播机制、自动/手动抛出方式(throw/throws的区别),以及两种核心处理方式:声明抛出和捕获处理(try-catch-finally)。文章还涵盖自定义异常的实现规则、断言的使用方法,并提供异常处理最佳实践,如避免空catch块、及时释放资源等。通过系统化的讲解,帮助开发者构建完整的异常处理知识体系,提升代码

yh云想的博客 1199

网站进行企业微信授权登录(附带代码超详细版)

企业微信的扫码登录官方文档 https://work.weixin.qq.com/api/doc/90000/90135/90988 企业微信扫码登录认证流程 上面是官方的图片,看上去比较复杂。因此我用直白简洁的语言梳理下流程。 1、首先在自己的网站上获取到企业微信登录的二维码(二维码怎么获取稍后再说,这里想象下你已经有了一个二维码) 2、你拿着手机扫描二维码,确认登录之后,页面就会自己进行重定向的跳转,跳转的url如何配置下面再讲,但是注意,这个重定向的url可以是内网地址 3、重定向到指

Gzf的博客 1万+

StarUML最新版汉化与破解二合一教程:5分钟搞定永久使用

本文提供StarUML最新版的高效使用指南,涵盖从安装到深度定制的全流程优化方案。包括软件获取最佳实践、界面个性化设置、核心建模技巧、团队协作策略及性能优化建议,帮助架构师和开发团队提升UML建模效率。特别推荐版本控制集成和文档自动化输出方案,适用于各类规模的项目开发。

weixin_42530732的博客 450

全面的 Java 学习路线:从零基础到高级开发

Java 是一门既经典又充满活力的编程语言,涵盖了从基础语法到高级技术的各个层面。无论你是初学者还是有经验的开发者,都可以通过这条路线不断提升自己的 Java 技能。通过合理的学习规划、深入的项目实践以及参与开源社区,你将能够在 Java 开发的道路上走得更远。

Hellc007的博客 5812

电力-平衡式IEC 60870-5-101规约报文解析

本文详细介绍了电力自动化中平衡式IEC 60870-5-101规约的应用,包括链路建立与初始化、对时、遥控操作、数据上送和总召唤等关键步骤,通过实例解析了报文格式和交互过程,是理解配网自动化通信的重要参考资料。

让你爱上电路设计 5682

【Java全栈】Java全栈工程师技能树全解析:从初级到高级的进阶之路

Java全栈工程师的成长是一条从“广度”到“深度”的路径: 初级阶段:掌握核心语法与工具链,能独立完成简单模块开发。 中级阶段:扩展技术栈,具备全栈项目协作能力。 高级阶段:专注架构设计,解决复杂系统问题,引领技术决策。

杰西笔记 1416

labelImg使用教程

Anaconda环境 安装 Anaconda 之后,在开始菜单下找到 Anaconda 文件夹 找到 Anaconda Prompt 点击运行 安装 labelImg pip install labelImg #直接命令行输入 启动 labelImg labelImg #直接命令行输入名称即可 labelImg界面 开始标注 快捷键:W(创建方框),A(上一张),D(下一张) XML文件示例 <annotation> <folder>夜读</folder>

G果的博客 3万+

8 卡 GPU 服务器与 NVLink/NVSwitch 互联技术

NVLink 是一种点对点的高速互连技术,单条 NVLink 就是一条全双工双路信道,每条 NVLink 链路可以将 2 个 GPU 直连起来,并且每个 GPU 可以提供多条 NVLink 接口连接多个 GPU。另外,PCIe Switch 互联拓扑中的 GPU 之间可能存在 GPU0→Switch0→CPU0→CPU1→Switch1→GPU7 的通信链路,它的通信不可避免的存在一定的延迟,因而更适合用于对信号效率不敏感且追求性价比的使用场景,如:推理、云计算等领域。本文讨论的是单机 GPU 卡间互联。

烟云的计算 4262

Java异常处理全面指南:从基础到高级实践

异常(Exception)是程序在执行过程中发生的意外事件,它会打断正常的指令流。在Java中,异常是一个对象,它封装了错误事件的信息。通俗理解:就像生活中的意外情况,比如你正开车去上班(正常流程),突然爆胎了(异常),你需要停下来处理这个意外情况。// 自定义异常类// 使用自定义异常"余额不足,缺少: " + (amount - balance),Java内置异常无法准确描述你的问题需要携带额外的错误信息希望对特定业务错误进行特殊处理需要统一异常处理逻辑。

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1081

基于Blender的AI插件——2D图片生成3D模型

只需5分钟即可从图片到可编辑3D模型,支持Blender全版本兼容。

这里汇聚了前沿的技术分享与实用的开发技巧,带你探索从创意到企业的技术创业之路。 2574

Java异常处理全解析:从崩溃到优雅恢复的秘诀

主要介绍Java异常处理体系,Java 异常处理体系包括多种类型的异常和处理机制,合理使用异常处理可以提高程序的健壮性和可维护性。

qq_45438032的博客 2579

OpenClaw一人公司落地案例:本地商家营销智能体月赚3万的秘密

角色:本地商家营销专家## 核心目标为商家生成高转化率的抖音营销策略,最大化 ROI。## 输入数据- 商家名称: "XX奶茶店"- 过去 30 天视频播放量: 12,000- 客单价: 28 元- 竞品平均播放量: 15,000- 市场趋势: rising## 策略生成规则1. **内容类型**:根据客单价推荐- < 30 元:美食探店 + 优惠券- > 30 元:场景化故事 + 会员权益2. **发布时间**:根据历史数据- 18:00-20:00 高峰期。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 542

Vivado报错-4 [Routed 35-3424] SLL Assignment failed ILP VU19P

Vivado报错[Routed 35-3424] SLL Assignment failed ILP VU19P

weixin_39896700的博客 1408

Java异常处理全解析:从基础到实战的最佳实践

异常是程序运行时的不正常情况,例如文件不存在、网络中断等。Java通过异常机制将错误处理代码与正常业务逻辑分离。异常与错误的区别Error:JVM无法处理的严重问题(如),通常不需要捕获。Exception:程序可捕获处理的异常(如// Error示例(不可捕获)throw new OutOfMemoryError("JVM内存耗尽");继承核心原则捕获最具体的异常类型永远不忽略异常确保资源释放(try-with-resources)工具推荐Lombok的。

ztt123654的博客 840

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

深入解析Java 异常处理:从基础到实战

Java 中的异常指程序执行过程中发生的不正常事件。这些异常被大致分为两类:Error 和 Exception。Error 通常代表严重的、不可恢复的问题,例如系统内部错误或资源耗尽等情况,一般来说,程序很难对 Error 进行有效的处理。而 Exception 则是一般性的问题,是程序在正常运行过程中可能遇到的异常情况,这类异常是可以被处理的。Exception 又进一步细分为运行时异常和编译时异常。1. 编译时异常编译时异常是在程序编译阶段被检测到的异常,需要开发者进行处理,否则程序无法通过编译。

qq_25699299的博客 1079

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Java 异常处理全解析:从基础到自定义异常的实战指南

异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。异常发生在程序运行期间,它影响了正常的程序执行流程。要理解java异常处理是如何工作的,你需要掌握以下三种类型的异常Exception检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。错误Error。

m0_71539493的博客 949

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Spring 异常处理全解析:从基础到实战

首先创建统一响应类 Result,确保无论成功还是失败,返回格式一致:@Data// 状态码:200成功,其他为错误(如400参数错误、500系统异常)// 提示信息// 响应数据(成功时返回,失败时可为null)// 成功响应(带数据)result.setMessage("操作成功");

开往1982的博客 697

Java 异常处理全解析:从原理到实战,让你的代码更健壮

Java异常处理机制是保证程序健壮性的核心技术。本文系统讲解了Java异常体系结构(Error与Exception的区别、运行时异常与编译时异常的特性比较),详细解析了try-catch-finally、throws、throw三种核心处理机制,并重点介绍了自定义业务异常的实现方法。通过文件操作和参数校验两个实战案例,展示了异常处理的最佳实践,包括使用try-with-resources自动管理资源、设计包含错误码的自定义异常等。最后总结了10条异常处理原则,如避免吞噬异常、异常信息要具体等,帮助开发者编写

qq_40303030的博客 1309

Java Scanner 类全解析:从基础输入到高级交互的实战指南

之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入。java.util.Scanner 是Java5 的新特征,我们可以通过Scanner 类来获取用户的输入。作为 Java 标准库中处理用户输入的核心工具,Scanner 提供了丰富的方法支持,本文将整合课程内容,深度解析 Scanner 的底层原理与实践技巧。

m0_71539493的博客 721

[技术资料]万字解析Java:从基础到高级,掌握Java核心概念

Java基础内容整理

liliYoung_的博客 1141

Java异常处理全解析:从基础到自定义

本文详细介绍了Java中的异常处理机制,从异常的定义与分类到异常的基本处理方式,再到自定义异常的实现。异常是程序运行时发生的错误或意外情况,分为Error(系统级错误)和Exception(可处理的异常)。Exception进一步分为运行时异常(RuntimeException)和编译时异常(Checked Exception)。运行时异常在编译阶段不会报错,而编译时异常在编译阶段就会提示错误。

2402_88461821的博客 1228

[Java基础] 异常处理机制

本文主要阐述了Java中的异常处理机制,以及罗列了一些常见的检查型异常、运行时异常和错误,最后给出了异常处理的最佳实践。

MCC_MCC_MCC的博客 1230
上一篇: Java集合框架学习笔记
下一篇: Java常用类详解:从Object到Random,一文掌握Java核心类库
StackNoOverflow
博客等级 码龄1年 22粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值