Java案例如何全局捕获异常?

wen java案例 9

本文目录导读:

Java案例如何全局捕获异常?

  1. Web应用全局异常处理(Spring Boot)
  2. Java桌面应用全局异常捕获
  3. 多线程环境下的全局异常捕获
  4. Filter方式全局异常捕获(Web应用)
  5. 最佳实践建议

在Java中全局捕获异常主要有以下几种方式,下面按常见场景详细介绍:

Web应用全局异常处理(Spring Boot)

使用@ControllerAdvice + @ExceptionHandler

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 处理所有未捕获的异常
    @ExceptionHandler(Exception.class)
    public Result<String> handleException(Exception e) {
        // 记录日志
        log.error("系统异常", e);
        return Result.error(500, "系统繁忙,请稍后重试");
    }
    // 处理特定异常
    @ExceptionHandler(IllegalArgumentException.class)
    public Result<String> handleIllegalArgument(IllegalArgumentException e) {
        return Result.error(400, e.getMessage());
    }
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public Result<String> handleBusinessException(BusinessException e) {
        return Result.error(e.getCode(), e.getMessage());
    }
}

自定义业务异常

public class BusinessException extends RuntimeException {
    private Integer code;
    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }
    public Integer getCode() {
        return code;
    }
}

Java桌面应用全局异常捕获

使用UncaughtExceptionHandler

public class GlobalExceptionCatcher {
    public static void main(String[] args) {
        // 设置全局异常处理器
        Thread.setDefaultUncaughtExceptionHandler(
            new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    // 记录日志
                    System.err.println("线程 " + t.getName() + " 发生未捕获异常:");
                    e.printStackTrace();
                    // 显示友好提示
                    JOptionPane.showMessageDialog(null,
                        "程序发生异常,请检查日志文件",
                        "系统异常",
                        JOptionPane.ERROR_MESSAGE);
                }
            }
        );
        // 启动应用程序
        SwingUtilities.invokeLater(() -> {
            new MyApplication().start();
        });
    }
}

完整的Swing应用示例

public class SwingExceptionHandler {
    public static void main(String[] args) {
        // 1. 设置线程异常处理器
        Thread.setDefaultUncaughtExceptionHandler(
            (thread, throwable) -> handleException(throwable)
        );
        // 2. 设置AWT事件异常处理器
        System.setProperty("sun.awt.exception.handler", 
            AWTExceptionHandler.class.getName());
        // 3. 启动应用
        EventQueue.invokeLater(() -> {
            try {
                new MyFrame().setVisible(true);
            } catch (Exception e) {
                handleException(e);
            }
        });
    }
    private static void handleException(Throwable e) {
        // 记录异常到文件
        try (FileWriter fw = new FileWriter("error.log", true);
             PrintWriter pw = new PrintWriter(fw)) {
            e.printStackTrace(pw);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        // 显示友好提示
        JOptionPane.showMessageDialog(null,
            "系统出现异常,请查看error.log文件了解详情",
            "错误",
            JOptionPane.ERROR_MESSAGE);
    }
}
// AWT异常处理器
public class AWTExceptionHandler {
    public void handle(Throwable throwable) {
        SwingExceptionHandler.handleException(throwable);
    }
}

多线程环境下的全局异常捕获

线程池异常处理

public class ThreadPoolExceptionHandler {
    public static void main(String[] args) {
        // 创建自定义线程工厂
        ThreadFactory threadFactory = new ThreadFactoryBuilder()
            .setUncaughtExceptionHandler((thread, throwable) -> {
                System.err.println("线程 " + thread.getName() + 
                    " 发生异常: " + throwable.getMessage());
            }).build();
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(5, threadFactory);
        // 或者直接设置
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
            5, 10, 60, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),
            new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r);
                    t.setUncaughtExceptionHandler(
                        (thread, throwable) -> {
                            System.err.println("异常处理: " + 
                                throwable.getMessage());
                        }
                    );
                    return t;
                }
            }
        );
    }
}

CompletableFuture异常处理

public class CompletableFutureExceptionHandler {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture
            .supplyAsync(() -> {
                if (Math.random() > 0.5) {
                    throw new RuntimeException("异步任务异常");
                }
                return "成功";
            })
            .exceptionally(throwable -> {
                System.err.println("捕获异常: " + throwable.getMessage());
                return "默认值";
            })
            .handle((result, throwable) -> {
                if (throwable != null) {
                    System.err.println("异常处理: " + throwable.getMessage());
                    return "处理异常";
                }
                return result;
            });
    }
}

Filter方式全局异常捕获(Web应用)

@WebFilter("/*")
public class ExceptionFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {
            // 全局异常处理
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            // 记录日志
            log.error("请求 {} 发生异常", req.getRequestURI(), e);
            // 返回统一错误响应
            resp.setContentType("application/json;charset=UTF-8");
            resp.getWriter().write(JSON.toJSONString(
                Result.error(500, "系统异常")
            ));
        }
    }
}

最佳实践建议

组合使用多种捕获方式

@Configuration
public class ExceptionConfig {
    // 1. 全局异常处理
    @Bean
    public GlobalExceptionHandler globalExceptionHandler() {
        return new GlobalExceptionHandler();
    }
    // 2. 线程异常处理器
    @PostConstruct
    public void initThreadExceptionHandler() {
        Thread.setDefaultUncaughtExceptionHandler(
            (thread, throwable) -> {
                log.error("线程 [{}] 发生未捕获异常", 
                    thread.getName(), throwable);
                // 发送告警通知
                alertService.sendAlert(throwable);
            }
        );
    }
    // 3. 自定义异常处理策略
    @Bean
    public ExceptionHandler exceptionHandler() {
        return new SimpleMappingExceptionResolver() {{
            setDefaultErrorView("error");
            setExceptionAttribute("exception");
            setDefaultStatusCode(500);
            // 特定异常映射
            setExceptionMappings(new Properties() {{
                put("java.lang.IllegalArgumentException", "error-400");
                put("com.example.BusinessException", "error-biz");
            }});
        }};
    }
}

异常处理注意事项

  1. 不要过度捕获:只捕获确实需要全局处理的异常
  2. 区分异常类型:业务异常、系统异常、第三方异常应分开处理
  3. 保留原始异常:在包装异常时保留原始异常信息
  4. 日志记录:所有全局捕获的异常都要记录日志
  5. 友好提示:用户界面显示友好的错误信息,不要暴露技术细节

选择哪种方式取决于应用类型和需求,通常Web应用推荐使用@ControllerAdvice,桌面应用使用UncaughtExceptionHandler

抱歉,评论功能暂时关闭!