错误处理
- 当错误发生时,程序员有责任确保代码正常工作。
- 错误处理很重要,但如果它搞乱了代码逻辑,就是错误的做法。
使用异常而非返回码
7-1
public class DeviceController{
...
public void sendShuntDown(){
DeviceHandel handle = getHandel(DEV1);
//Check the ststus of the device
if(handle != DeviceHandel.INVAILD){
//Save the device status to the record field
retrieveDeviceRecord(handle);
//if not suspended ,shut down
if(record.getStatus()!= DEVICE_SUSPENDED){
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
} else{
logger.log("Device suspended .Unable to shut down");
}
}else{
logger.log("Invalid handel for :"+DEV.toString());
}
}
...
}
代码7-1的问题在于,调用者在调用这段代码之后必须即刻检查错误,如果返回了不同的错误代码,调用者还要做出不同的逻辑处理,这个步骤也是我们常常忽略的。
7-2
public class DeviceController{
...
public void sendShutDown(){
try{
tryToShutDown();
}catch(DeviceShutDownError e){
logger.log(e);
}
}
private void tryToShutDown() throws DeviceShutDownError{
DeviceHandle handle = getHandle(DEV1);
DeviceRecord record = retrieveDeviceRecord(handle);
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
}
private DeviceHandle getHandle(DeviceID id){
...
throw new DeviceShutDownError("Invalid handle for:" + id.toString());
...
}
}
遇到错误时,最好抛出一个异常,这会保持调用者代码的整洁度,而且其逻辑不会被错误处理搞乱。
先写Try-Catch-Finally语句
- 某种意义上,try代码块就像是事务,catch代码块将程序维持在一种持续状态
使用不可控异常
- 如果你在方法中抛出可控异常,而catch语句在三个层级之上,你就得在catch语句和抛出异常之间繁荣每个方法签名中声明该异常。
- 封装被打破,因为在抛出路径中的每个函数都要去了解下一层级的异常细节。
给出异常发生的环境的说明
- 你抛出的每个异常,都应当提供足够的环境说明,以便判断错误的来源和处所。
依调用者需要定义异常类
- 当我们在应用程序中定义异常类时,最重要的考虑应该是他们如何被捕获。
ACMEPort port = new ACMEPort(12);
try{
paro.open();
} catch(DeviceResponseException e){
reportPortError(e);
logger.log("Device response exception" ,e);
}catch(ATM1212UnlockedException e){
reportPortError(e);
logger.log("Unlock exception" ,e);
}catch(GMXError e){
reportPortError(e);
logger.log("Device response exception");
}finally{
...
}
LocalPort port = new LocalPort(12);
try{
port.open();
}catch(PortDeviceFailure e){
reportError(e);
logger.log(e.getMessage(),e);
}finally{
...
}
public void LocalPort{
private ACMEPort innerPort;
public LocalPort(int portNumber){
innerPort = new ACMEport(portNumber);
}
public void open(){
try{
innerPort.open();
}catch(DeviceResponseException e){
reportPortError(e);
logger.log("Device response exception" ,e);
}catch(ATM1212UnlockedException e){
reportPortError(e);
logger.log("Unlock exception" ,e);
}catch(GMXError e){
reportPortError(e);
logger.log("Device response exception");
}finally{
...
}
}
}
定义常规流程
- 创建一个类或者配置一个对象,用来处理特例。
特例模式:
try{
MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_totle += expenses.getTotal();
}catch(MealExpensesNotFound e){
m_total += getMealPerDiem();
}
MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_totle += expenses.getTotal();
public class PerDiemMealExpenses implements MealExpenses{
public int getTotal(){
...
}
}
别返回null值
- 如果你打算在方法中返回null值,不如抛出异常,或是返回特例对象。
public List getList(){
...
if(lis != null){
return lis;
}else {
return Collections.emptyList();
}
}
- 尽量避免NullPointerException的出现,代码也就更整洁了。
别传递null值
- 在方法中返回null值是糟糕的做法,但将null值传递给其他方法就更糟糕了。
- 没有良好的方法能对付由调用者意外传入的null值,恰当的做法就是禁止传入null值.