论坛首页 Java企业应用论坛

《Clean Code》总结 异常

浏览 1794 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-03-14   最后修改:2010-03-14
1.使用异常而不是错误码
如果使用错误码,调用者,必须在方法调用后立即检查结果,如果多次调用都放回错误码,就会造成复杂的多层嵌套结构。
if (deletePage(page) == E_OK) {
    if (registry.deleteReference(page.name) == E_OK) {
        if (configKeys.deleteKey(page.name.makeKey()) == E_OK){
            logger.log("page deleted");
        } else {
            logger.log("configKey not deleted");
        }
    } else {
        logger.log("deleteReference from registry failed");
    }
} else {
    logger.log("delete failed");
    return E_ERROR;
}

2.使用uncheck异常
java世界就checked exception的优劣争论了很久。没有checked异常的也能构建robust的程序。为了robust而使用checked异常的代价太高了。checked异常最大的问题在于它是的程序违反了 开放/封闭原则 调用者不得不捕捉异常或者声明抛出异常。如果底层的异常修改了,高层代码也要修改。如果异常在较高层次处理,就会造成一串的修改。

3.为了调用者的方便,封装异常调用代码
很多标准库或者第三方库的方法调用会抛出多个checked异常,对一长串异常处理的代码显得太冗长,而直接捕捉Exception又会丢失很多细节。一个解决方法就是,使用单独的类或方法封装抛出异常的方法调用,做一些处理后抛出unchecked异常,方便上层调用。
ACMEPort port = new ACMEPort(12);
try {
	port.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 {
…
}
做如下封装
public class LocalPort {
	private ACMEPort innerPort;

	public LocalPort(int portNumber) {
		innerPort = new ACMEPort(portNumber);
	}

	public void open() {
		try {
			innerPort.open();
		} catch (DeviceResponseException e) {
			throw new PortDeviceFailure(e);
		} catch (ATM1212UnlockedException e) {
			throw new PortDeviceFailure(e);
		} catch (GMXError e) {
			throw new PortDeviceFailure(e);
		}
	}
}

高层代码只需要处理DeviceResponseException。这样做也使得第三方代码的传播度更小,也更方便mock方法调用。

4.不使用异常处理正常逻辑,比如下面的代码
try {
	MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
	m_total += expenses.getTotal();
} catch(MealExpensesNotFound e) {
	m_total += getMealPerDiem();
}

异常弄乱了正常的逻辑。解决方法是让ExpenseReportDAO始终返回MealExpenses,如果MealExpenses not found,可是返回一个特殊的MealExpenses
public class PerDiemMealExpenses implements MealExpenses {
	public int getTotal() {
		// return the per diem default
	}
}

这叫着SPECIAL CASE PATTERN [Fowler],You create a class or configure an object so that it handles a special case for you.

5.不要返回Null。
方法调用如果允许放回null,会大大增加调用者的复杂度。可以考虑抛出异常,或者使用Null Object或者特殊的对象。例如
List<Employee> employees = getEmployees();
if (employees != null) {
	for (Employee e : employees) {
		totalPay += e.getPay();
	}
}
------
public List<Employee> getEmployees() {
	if (.. there are no employees ..)
		return Collections.emptyList();
}

如果没有Employee,就返回一个空的List,这样调用者可以不用做特殊的处理。

6.不要传递null到方法。
如果参数可为null,方法不得不做必要的检查,代码会很冗余,而且没有很好解决方案。
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics