본문 바로가기
함수형 프로그래밍

[ch.10] 예외 처리

by tjdgus 2024. 7. 4.

현재까지 접한 프로젝트에서 어떻게 예외를 처리하고 있는 지 살펴봤다.

// 잘못된 값이 넘어왔거나 값이 없을 때
if (param == null) {
    throw new xxxException("F", "값을 다시 확인해주세요.");
}

// DB 조회 시 결과 데이터가 없을 때
if (list == null || list.size() == 0) {
    throw new xxxException("데이터가 없습니다.");
}

// api 통신 예외 처리
if (...) {
    throw new xxxException(ErroCode.XXX.getCode()); // E.200.x    
}

// if/else 지옥을 어떻게 마무리해야할 지 모를 때
if (...) {
    // ...
} else if (...) {
    // ...
} else {
    throw new xxxException("알 수 없는 오류입니다.");   
}

 

던져진 예외는 오류 메시지를 담아 사용자에게 팝업으로 보여진다.

 

위의 코드들은 무분별하게 예외를 던지고 있고, 문서 없이는 이해할 수 없는 에러 코드를 주고 있다.

 

예외 발생 시

  • 실행되는 코드 중단
  • 예외 객체 생성
  • 스택 트레이스를 캡처하여 예외 객체에 저장
  • 예외 처리기(catch)를 찾기 위한 스택 언와인딩

이러한 과정들을 거치는데 모든 해결을 예외로 처리한다면 위 과정들을 여러번 반복하게 되고,

예외 처리로 인한 성능 저하의 원인이 될 수 있다.

 

반대로 (객체의 상태를 변경하는 로직에서) 예외 처리가 제대로 되지 않는다면 예상치 못한 동작을 하게 되고,

예상치 못한 동작을 하는 것은 예외를 throw 하는 것보다 위험하다.

 

문제를 해결하기 위해 더 큰 문제를 만드는 상황이 발생한다.

 

예외는 문제를 해결할 다른 방법이 없을 때 사용하는 최후의 수단이며,

문제를 놓치지 않고 코드를 더 안정적으로 작동하게 하는 방법이다.

 

Stack Unwinding - 스택 되감기
- JVM은 호출 스택을 따라가면서 예외를 처리할 수 있는 가까운 catch 블록을 찾는데, 이 과정을 스택 언와인딩이라 한다.
- 예외가 발생한 메서드부터 시작하여 해당 메서드를 호출한 상위 메서드로 거슬러 올라간다.
- 적절한 예외 처리기가 없다면 JVM에 의해 프로그램은 종료되고, 스택 트레이스 정보가 출력된다.

 

 

좋은 예외 처리

 

명확하고 구체적인 예외 메시지

  • 애매한 메시지는 오히려 사용자에게 혼란을 줄 수 있다.
  • '알 수 없는 오류가 발생했습니다', '값을 다시 확인해주세요.'

 

의미를 담고 있는 예외

  • 코드를 읽는 사람이 예외 이름만 보고도 해당 예외가 발생한 이유를 어느 정도 추측할 수 있어야 한다.
// bad
throw new BusinessException("F", "값을 다시 확인해주세요.");

// so_so
throw new EmptyParameterException("Required value is missing.");
throw new InvalidInputException();

 

 

일반적인 흐름 제어에 사용 지양

if (param == null) {
    throw new NoDataFoundError();
}
  • 데이터가 없는 일반적인 상황에서 예외를 던지는 것보다 null 값이나 기본 값을 제공하는 것이 좋다.
    • null을 반환하는 것보다 대체 값이나 빈 자료구조 등을 반환하는 것이 좋다.
if (param == null) {
    param = "default"; // 기본 값 설정
}

if (list == null || list.size() == 0) {
    list = new ArrayList<>(); // 빈 리스트로 초기화
}
  • 예외는 오직 예외적인 경우에만 사용해야 한다.