java异常 | 处理规范、全局异常、Error处理

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: java异常 | 处理规范、全局异常、Error处理

异常类型

异常大类 发生场景
Throwable 所有异常的根类
Error 由虚拟机或系统引发的异常
Exception RuntimeException :运行时异常,不需要显式捕获或声明;非RuntimeException:必须显式捕获或声明的异常

显示声明异常:

①:try-catch

try {
    // 执行可能抛出Runtime异常的代码
} catch (ClassCastException e) {
    throw new CustomException("业务处理异常", e);
}

②方法签名

public void method() throws ClassCastException{
    // 可能抛出Runtime的代码
}

异常处理规范

异常包装

   规范:

       捕获异常后,将其包装为自定义异常,并添加更多的上下文信息。


按业务划分异常:可以更好地反映业务逻辑和场景,使得异常的处理更加准确和精细化。例如,在电商应用中可以定义订单异常、库存异常、支付异常等来表示不同的业务异常情况。


按层划分异常:可以更好地将异常的处理与各层的责任分离开来。例如,在多层架构中,可以定义表示数据访问层异常的数据库异常、表示业务逻辑层异常的业务异常、表示展示层异常的界面异常等。


按其他需求划分异常常:例如按照功能模块、错误类型、系统模块等进行划分。

 代码示例:

try {
    // 执行可能抛出异常的代码
} catch (Exception e) {
    // 将异常包装为自定义异常,添加更多上下文信息
    throw new CustomException("业务处理异常", e);
}

异常传递

   规范:

       在方法签名中明确声明可能抛出的受检异常,以便上层调用者知晓,并在适当的层次处理异常。


   代码示例:

public void method() throws IOException {
   // 可能抛出IOException的代码
}

异常日志记录

   规范:

       在异常处理过程中,记录异常相关的信息,如异常类型、异常堆栈信息、触发异常的位置等。


   代码示例:

try {
   // 可能抛出异常的代码
} catch (Exception e) {
   logger.error("异常类型: " + e.getClass().getSimpleName());
   logger.error("异常堆栈信息: ", e);
}

异常处理的最佳实践

   规范:

       避免捕获过宽的异常类型,尽量捕获具体的异常类型;在合适的地方捕获异常,不要滥用异常捕获;及时关闭资源,避免资源泄露等。


   代码示例:

try {
   // 可能抛出特定异常的代码
} catch (SpecificException se) {
   // 处理特定异常的逻辑
}

全局异常处理

优点:

   @ControllerAdvice+@ExceptionHandler注解确保捕获和处理Controller层的异常。

代码示例:

/**
 * @Description: 全局异常类
 * @Version: 1.0
 */
@ControllerAdvice//使用该注解表示开启了全局异常的捕获
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    /**
     * 处理空指针的异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, NullPointerException e) {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生空指针异常!原因是:", e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResultMsgEnum.EXECUTE_FAIL.getMsg());
    }
    /**
     * 处理索引越界异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = IndexOutOfBoundsException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, IndexOutOfBoundsException e) {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("索引越界异常!原因是:", e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResultMsgEnum.EXECUTE_FAIL.getMsg());
    }
    /**
     * 处理类未找到异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = ClassNotFoundException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, ClassNotFoundException e) {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生类未找到异常!原因是:", e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResultMsgEnum.EXECUTE_FAIL.getMsg());
    }
    /**
     * 处理SQL异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = SQLException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, SQLException e) {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生SQL异常!原因是:", e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResultMsgEnum.EXECUTE_FAIL.getMsg());
    }
    /**
     * 处理IO异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = IOException.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, IOException e) {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("发生IO异常!原因是:", e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResultMsgEnum.EXECUTE_FAIL.getMsg());
    }
    /**
     * 处理其他异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public FrontResult exceptionHandler(HttpServletRequest req, Exception e) {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("未知Exception!原因是:", e);
        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResultMsgEnum.EXECUTE_FAIL.getMsg());
    }
    /**
     * 处理Error异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Error.class)
    @ResponseBody
    public FrontResult errorHandler(HttpServletRequest req, Error e) {
        logger.error("URL : " + req.getRequestURL().toString());
        logger.error("HTTP_METHOD : " + req.getMethod());
        logger.error("未知Error!原因是:", e);
        // 发送警报通知
        sendAlertNotification();
        // 执行清理操作(关闭数据库连接、释放资源等)
        cleanup();
        // 终止应用程序
        System.exit(1);
    }
}

注意:

   全局异常处理应该是最后的防线,用于捕获未被处理的异常。在应用程序的各个层次中,尽量在局部进行异常处理,以确保能够在发生异常时立即采取适当的措施

Error类型的异常如何处理

   对于Java中的Error类型异常,通常是指严重的系统级错误,它们通常无法被应用程序处理或恢复,并且可能会导致应用程序的非正常终止,所以Error类型的异常一定要被开发人员重视。

常见Error异常

image.png

处理建议

   以下是处理Error类型异常的一些常见做法:

1. 不要捕获后不处理:

   Error类型的异常会导致应用程序无法正常运行,处理这些异常的主要目标是尽快终止程序的执行,以避免进一步的损害或数据丢失。即时捕获记录错误信息后,也应继续抛出异常,让这些异常冒泡到应用程序的顶层,由Java虚拟机或操作系统来处理。

2. 记录错误日志:

   当发生Error类型异常时,及时记录错误信息到日志中,以便后续的故障排查和分析。可以使用日志框架(如log4j、logback等)、或java虚拟机的错误日志来记录错误信息,并确保日志配置正确,以便及时获取异常的详细信息。

//配置java虚拟机错误日志
java -XX:ErrorFile=/path/to/error.log -jar xxxxx.jar

3. 异常监控和报警:

   设置合适的异常监控和报警机制,当系统发生Error类型异常时,及时通知相关人员或团队尽快处理。可以使用监控工具和服务(如Prometheus、Grafana等)来实现异常监控和报警功能。

4. 优雅降级:

   在面对严重的Error异常时,可以考虑进行优雅降级处理。例如,通过切换到备用服务、提供默认值或警告消息等方式,尽量保持系统的可用性,并减少对用户的影响。

结论

   在面对Error异常时,重要的是及时记录、报警、定位问题,并采取适当的措施来保证系统的稳定性和可用性,及时发现及时处理。

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
4月前
|
Java Shell Maven
【Azure Container App】构建Java应用镜像时候遇无法编译错误:ERROR [build 10/10] RUN ./mvnw.cmd dependency:go-offline -B -Dproduction package
在部署Java应用到Azure Container App时,构建镜像过程中出现错误:“./mvnw.cmd: No such file or directory”。尽管项目根目录包含mvnw和mvnw.cmd文件,但依然报错。问题出现在Dockerfile构建阶段执行`./mvnw dependency:go-offline`命令时,系统提示找不到可执行文件。经过排查,确认是mvnw文件内容异常所致。最终通过重新生成mvnw文件解决该问题,镜像成功构建。
164 1
|
5月前
|
Java 程序员 数据库连接
我们详细地讲解一下 Java 异常及要如何处理
我是小假 期待与你的下一次相遇 ~
132 1
|
6月前
|
Java
Java 中 Exception 和 Error 的区别
在 Java 中,`Exception` 和 `Error` 都是 `Throwable` 的子类,用于表示程序运行时的异常情况。`Exception` 表示可被捕获和处理的异常,分为受检异常(Checked)和非受检异常(Unchecked),通常用于程序级别的错误处理。而 `Error` 表示严重的系统级问题,如内存不足或 JVM 错误,一般不建议捕获和处理。编写程序时应重点关注 `Exception` 的处理,确保程序稳定性。
200 0
|
8月前
|
SQL druid Oracle
【YashanDB知识库】yasdb jdbc驱动集成druid连接池,业务(java)日志中有token IDENTIFIER start异常
客户Java日志中出现异常,影响Druid的merge SQL功能(将SQL字面量替换为绑定变量以统计性能),但不影响正常业务流程。原因是Druid在merge SQL时传入null作为dbType,导致无法解析递归查询中的`start`关键字。
|
8月前
|
SQL Java 中间件
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
在BeetISQL 2.13.8版本中,客户使用batch insert向yashandb表插入数据并尝试获取自动生成的sequence id时,出现类型转换异常。原因是beetlsql在prepareStatement时未指定返回列,导致yashan JDBC驱动返回rowid(字符串),与Java Bean中的数字类型tid不匹配。此问题影响业务流程,使无法正确获取sequence id。解决方法包括:1) 在batchInsert时不返回自动生成的sequence id;2) 升级至BeetISQL 3,其已修正该问题。
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
|
9月前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
592 14
|
9月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
1746 5
|
10月前
|
算法 Java API
Java 方法注释:规范、实用和高质量的写法
本文深入探讨了如何编写高质量的 Java 方法注释
611 11
|
10月前
|
Java Windows
【Azure Function】部署Java Function失败:报错deploy [ERROR] Status code 401和警告 'China North 3' may not be a valid region
1:deploy [ERROR] Status code 401, (empty body). 2: China North 3 may not be a valid region,please refer to https://aka.ms/maven_function_configuration#supported-regions for values. 3:  <azure.functions.maven.plugin.version>1.36.0</azure.functions.maven.plugin.version>
177 11
|
12月前
|
安全 IDE Java
Java常见规范及易忘点
遵循Java编程规范和注意易忘点是提高代码质量和可维护性的关键。通过规范的命名、格式、注释和合理的代码组织,可以让代码更加清晰和易于维护。同时,注意空指针检查、线程安全、集合框架和字符串操作等常见易忘点,可以减少程序错误,提高运行效率。结合单一职责原则、面向接口编程和合理的异常处理,能够编写出高质量的Java代码。希望本文能够帮助Java开发者提升编码水平,写出更高效、更可靠的代码。
129 2