翻译:疯狂的技术宅
原文标题:Exception handling strategy
原文链接:http://programmergate.com/exc...
本文首发微信公众号:充实的脑洞
在本文中,我们介绍了在OOP应用中处理异常的常见策略,这些策略符合最佳的异常处理技术,可以在任何应用中使用。
1. 概述
下图提供了策略概述,它展示了从检测阶段到处理阶段的异常处理流程。该图需要从下往上进行阅读:
- Error detection: 在策略的底部是错误检测,这是发生异常的地方,它要么由程序进行检测,要么由一些外部调用引发。
- Local exception handling: 在第二级是本地异常处理,检测错误的类尝试在本地处理异常,例如:将请求发送到备份服务器,或等待X秒后再次尝试等...如果异常无法恢复,则将其传播到较高级别。
- Propagate exception to higher levels: 当本地错误处理不起作用时,该类收集诊断信息,再现和报告错误所需的所有信息,然后将该异常传到栈中。 如果检测到的异常不是低级别依赖(取决于低级别实现),那么它将被抛出,否则将被转换为自定义异常,以实现组件之间的解耦。
- Keep propagating if nothing to do with the exception: 较高级别的类将会继续将异常传到栈中, 只要它们与异常无关。同时关闭在传递路径的所有资源(例如文件、网络连接、释放分配的缓冲区等),并添加相关的上下文信息, 这将有助于确定错误的原因和严重性。
- Handle exception:在这个阶段,异常会到达一个负责处理它的类,异常所携带的所有错误信息都记录在此,并且根据异常的严重性,该类可以处理异常或者结束程序。
2. 自定义异常模板
实现异常处理策略时要做的第一件事就是,为程序的每个组件创建自定义异常,自定义异常如下所示:
public class ComponentException extends Exception {
private static final long serialVersionUID = 1L;
private int errorCode;
private String errorDescription;
private boolean isSevere;
public ComponentException() {
super();
}
public ComponentException(Exception ex) {
super(ex);
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getErrorDescription() {
return errorDescription;
}
public void setErrorDescription(String errorDescription) {
this.errorDescription = errorDescription;
}
public boolean isSevere() {
return isSevere;
}
public void setSevere(boolean isSevere) {
this.isSevere = isSevere;
}
}
以下描述了ComponentException类的属性:
- errorCode:识别此错误的唯一代码,errorCode告诉我们那里出错了,程序的所有错误代码应在静态类中进行预定义。该属性指示异常捕获代码应该怎样处理这个错误。
- errorDescription: 对错误的描述,描述了用户、程序操作人员和可能的程序开发人员所需的一切必要的细节,可以使他们了解到底发生了什么错误。
- isSevere: 指示该错误是否严重,此属性会在该异常根据错误的上下文遍历堆栈时进行更新,严重性会指示异常捕获代码是应该停止程序还是该继续处理。
3.引发异常
在检测到错误并无法从中恢复时,异常将向上传播到调用堆栈,直到到达处理它的某个 try-catch块。该异常可以按原样传递,也可转换为自定义异常。
3.1 抛出异常
如果异常不依赖于定期更改的低级实现或动态实现,那么你只需关闭打开的资源,并把异常积蓄传到调用栈而不去捕获它。下面是一个例子:
public void doSomething() throws SomeException {
try{
doSomethingThatCanThrowException();
} finally {
//close the opened resources
}
}
3.2 抛出自定义异常
当捕获的异常取决于低级别或动态实现时,它会被转换为一个特定的异常,然后重新启动调用堆栈。 下面是一个例子:
public Student readStudent(String id) throws SomeException {
try
{
// Some code which reads a student from oracle database
}
catch(SQLException ex)
{
DataAccessException dataAccessException = new DataAccessException(ex);
dataAccessException.setErrorCode(101); // we assume this code denotes student not found
dataAccessException.setErrorMessage("An error occurred while reading " +
"student with id: " + id + " from database");
dataAccessException.setSeverity(false);
throw dataAccessException;
}
}
只要它还没有到达能够处理它的类,异常就会继续传播。
P.S:强烈建议在异常传播到堆栈时更新异常的严重性,无论是异常被继续抛出,还是转换为自定义异常。
4. 捕获异常
在程序中,你需要捕获并响应来抛出异常,通常你需要在调用层次的顶部执行此操作。
捕获异常时首先要做的是记录它,通常我更喜欢使用printStackTrace(),之后的处理过程取决于异常的严重性:
- 如果严重,则通知开发人员和程序操作人员,并且结束程序。
- 如果不严重,则根据错误代码完成处理。通常有两种可能性,可以静默地从异常中恢复,或者通知最终用户并停止当前进程。
下面是一个例子:
try{
startTheWholeThing();
} catch(MyAppException e) {
e.printStackTrace();
if(e.isSevere())
{
notifyNonUsers(e);
// Halt the system gracefully
}
else
{
if(e.getErrorCode() == 100)
{
// do some silent recovery logic
}
else
{
notifyUsers(e);
}
}
}
以上是我在程序中处理异常时所遵循的策略,希望你能喜欢。
关注微信公众号:充实的脑洞, 一个技术宅的保留地 | |
---|---|
![]() |