文章目录
- 🚃异常类型
- 🎠显示声明异常:
- ①:try-catch
- ②方法签名
- 🚃异常处理规范
- ⚓️异常包装
- ⚓️异常传递
- ⚓️异常日志记录
- ⚓️异常处理的最佳实践
- 🚃全局异常处理
- ⛵️优点:
- ⛵️代码示例:
- ⛵️注意:
- 🚃Error类型的异常如何处理
- ⛲️常见Error异常
- ⛲️处理建议
- 1. 不要捕获后不处理:
- 2. 记录错误日志:
- 3. 异常监控和报警:
- 4. 优雅降级:
- ⛲️结论
🚃异常类型
异常大类 | 发生场景 |
---|---|
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) {
// 处理特定异常的逻辑
}
🚃全局异常处理
⛵️优点:
确保在应用程序的各个层次中,无论是控制器、服务层还是数据访问层,都能够捕获和处理异常。
⛵️代码示例:
/**
* @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异常
类型 | 发生场景 |
---|---|
OutOfMemoryError | 内存溢出错误,表示应用程序在申请内存时无法满足需求 |
StackOverflowError | 栈溢出错误,表示方法调用的层级过深,导致栈空间不足 |
NoClassDefFoundError | 找不到类定义错误,表示在运行时无法找到所需的类文件 |
NoSuchMethodError | 找不到方法错误,表示在运行时无法找到所需的方法 |
ExceptionInInitializerError | 表示在静态初始化期间发生异常 |
IllegalAccessError | 表示非法访问类、字段或方法 |
AbstractMethodError | 表示抽象方法没有被实现或覆盖 |
AssertionError | 断言错误,表示断言语句失败 |
⛲️处理建议
以下是处理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异常时,重要的是及时记录、报警、定位问题,并采取适当的措施来保证系统的稳定性和可用性,及时发现及时处理。