깔끔한 오류 처리가 깨끗한 코드를 만든다.
예외가 발생할 코드라면 try-catch-finally 문으로 시작하는 편이 낫다.
try-catch 구조로 범위를 정의하고, TDD를 통해 나머지 논리를 추가한다.
먼저 강제로 예외를 일으키는 테스트 케이스를 작성 후 테스트를 통과하게 코드를 작성하면 자연스럽게 try 블록의 트랜잭션 범위부터 구현하게 되므로 트랜잭션 본질을 유지하기 쉬워진다.
checked 예외를 사용할 때 드는 비용보다 이익이 더 클 때만 사용한다.
checked 예외는 하위 단계 메서드에 예외를 추가하면 모든 상위 단계 메서드에도 해당 예외를 정의해야 한다.
이는 OCP(개방-폐쇄 원칙)를 위반하고 캡슐화를 깨뜨린다.
오류를 정의할 때 가장 중요한 관심사는 오류를 잡아내는 방법이어야 한다.
예외에 대응하는 방식이 예외 유형과 무관하게 동일하다면 wrapper 클래스를 통해 예외 유형 하나만을 반환하도록 할 수 있다.
LocalPort port = new LocalPort(12)
try{
port.open();
} catch (PortDeviceFailure e) {
reportError(e)
logger.log(e.getMessage(), e);
} finally {
...
}
public class LocalPort {
private ACMEPort innerPort;
pblice 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);
}
}
...
}
// Before
try {
MealExpenses expenses = ExpenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();
} catch (MealExpenseNotFound e) {
m_total += getMealPerDiem();
}
// After
MealExpenses expenses = ExpenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();
public class PerDiemExpenses implements MealExpenses {
public int getTotal() {
// 기본값으로 일일 식비를 반환
}
}
null을 반환하는 코드는 호출자에게 문제를 떠넘긴다.
null 확인이 너무 많다면 예외를 던지는 것으로 바꾸거나 특수 사례 객체를 반환하도록 한다.
외부 API가 null을 반환한다면 wrapper 메소드를 구현해 예외를 던지거나 특수 사례 객체를 반환한다.
정상적인 인수로 null을 기대하는 API가 아닌 이상 메서드 인수로 null을 전달하는 것은 피한다.
대다수 프로그래밍 언어는 호출자가 실수로 넘기는 null을 적절히 처리하는 방법이 없으므로, 정책으로 null을 넘기지 못하도록 하는 것이 합리적이다.