🛁 [클린코드] 7장. 오류 처리
오류 코드보다 예외를 사용하라
오류 코드를 작성하는 방식으로 오류를 처리하면
비즈니스 로직과 오류 처리 로직이 뒤섞여버린다
비즈니스 로직 내에 오류가 발생할 만한 지점마다 if문을 사용해 오류 로그를 찍기 때문에
코드가 너무 복잡해지고 이해하기가 어려워진다
<오류 코드 사용한 코드>
public class DeviceController {
public void sendShutDown() {
DeviceHandle handle = getHandle(DEV1);
// 디바이스 상태를 점검한다.
if (handle != DeviceHandle.INVALID) {
// 레코드 필드에 디바이스 상태를 저장한다.
retrieveDeviceRecord(handle);
//디바이스가 일시정지 상태가 아니라면 종료한다.
if (record.getStatus() != DEVICE_SUSPENDED) {
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handel);
} else {
logger.log("Device suspended. Unable to shut down");
}
} else {
logger.log("Invalid handle for: " + DEV1.toString());
}
}
}
반면에 예외로 빼버리면
비즈니스 로직과 오류 처리 로직이 완전히 분리될수 있기 때문에
코드가 깔끔해진다
<예외로 처리한 코드>
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-finally문은
Try 블록 내에서 발생할 만한 오류를 catch 블록으로 빼버린다는 개념이기 때문에
오류 발생 가능 범위를 직접 정의할 수 있다
다시 말해 특정 예외가 발생할 만한 코드를 try 블럭 안에 가둬놓고 catch 블럭으로 예외를 처리하기 때문에
try 블록에서 무슨 일이 생기든지 호출자가 기대하는 상태를 정의하기가 쉬워진다는 것이다
public List<RecordedGrip> retrieveSection(String sectionName) {
try {
FileInputStream stream = new FileInputStream(sectionName);
} catch (Exception e) {
throw new StorageException("retrieval error", e);
}
return new ArrayList<RecordedGrip>();
}
Unchecked 예외를 사용하라
Checked 예외와 Unchecked 예외의 차이는
Checked 예외는 무조건 처리를 해줘야 한다는 것이고(처리 안 하면 컴파일 에러)
Unchecked 예외는 예외 처리를 강제하지 않는다는 것이다
그렇기 때문에 어떤 클래스에서 checked 예외를 사용하고 이를 처리하기 위해 throws문을 작성했다면
그 자식 클래스들도 똑같은 throws문을 계속 작성해야 하는 불편함이 생긴다
또한 자식 클래스에서 로직을 수정해 throws문을 추가하게 되었다면
모든 부모 클래스에 throws문을 추가해줘야하며
이는 OCP 원칙을 깨는 방식이다
따라서 웬만한 경우에는 unchecked 예외를 사용하여 캡슐화가 깨지지 않도록 하자
예외에 의미를 제공하라
예외를 던질 때는 실패한 연산 이름과 실패 유형도 언급하자
흐름을 끊지 말자
비즈니스 로직으로 충분히 해결할 수 있는 부분은 오류 처리를 하지 말자
프로그램이 중간에 중단되는 것은 그리 좋은 양상이 아니다
null을 반환하지 마라
null을 전달하지 마라
NullPointException이라는 귀찮은 예외가 발생하기 때문이다
따라서 null을 반환하기 보다는 특수 사례 객체를 반환하고
null은 절대! 전달하지 말자