예외 처리
개발을 하다보면 예외처리에 대한 고민을 많이 하게된다. 어느 부분에서는 예외를 명시해서 던지기만 하고 어느 부분에서는 예외를 원하는 방식으로 처리한다. 프로그램의 가독성과 유지보수성, 신뢰성을 위한 올바른 예외처리를 알아본다. 예외처리에 대해 Effective java 책을 보고 정리한 내용이다.
예외는 진짜 예외 상황에만 사용하라
예외는 예외 상황에서만 쓰이도록 설계되었기 때문에 정상적인 제어 흐름에서는 사용하면 안된다. 특정 상태에만 호출할 수 있는 “상태 의존적” 메서드는 “상태 검사” 메서드도 제공되어야 한다. 예를 들면 Iterator의 hasNext() 같은 메서드이다.
java에서 예외를 처리하는 throwable 타입으로 검사 예외, 런타임 예외, 에러 이렇게 세 가지가 제공된다.
검사 예외
“호출하는 쪽에서 복구하리라 여겨지는 상황에서는 검사 예외를 사용하자” 검사 예외를 사용하게 되면 호출하는 쪽에서 catch로 잡아 예외에 대한 처리를 하거나 상위 클래스로 예외를 던져 처리하게 된다. 메서드에 구성된 검사 예외는 메서드를 호출 했을 때 발생할 수 있는 결과를 반환한다.
런타임 예외 및 에러
“프로그래밍 오류를 나타낼 때는 런타임 예외를 사용하자” API 설계자는 전제 조건이 지켜지지 않은 경우 런타임 예외를 사용하는 것이 적합하다. 오류가 발생했을 때 복구 가능한 상황인지 프로그래밍 오류인지 명확하지 않은 경우에 런타임 예외를 사용한다.
복구가 가능하다고 판단되면 검사 예외를, 그렇지 않으면 런타임 예외를 사용하는 것이 적합하다. 런타임 에러는 JVM이 더 이상 작업을 수행할 수 없는 경우 발생되고 API 설계자가 Error 클래스를 상속받아 사용하는 경우는 없다. 검사 예외를 제외한 비검사 예외는 모두 RuntimeException을 상속받아 사용해야 된다.
상황에 적합한 예외를 사용하자
검사 예외를 사용하는 것은 프로그램이 안전하게 동작할 수 있게 예외를 제어할 수 있다는 장점이 있다. 하지만, 검사할 조건이 늘어나거나 예상하지 못하는 예외를 발생시킬 수 있다면, 비검사 예외를 사용하는 것이 적합하다. API 호출자가 예외 상황 발생 시 복구 가능하다면 Optional을 반환하는 방법을 선택할 수도 있다. Optional로는 제어하기 힘든 경우에만 검사 예외를 던지는 것이 적합하다고 볼 수 있다.
표준 예외를 사용하자
Java에는 표준 예외가 있다. IllegalArgumentException, illegalStatementException 등 많이 사용되는 표준 예외가 있다. API 호출 시 올바르지 않은 매개변수를 가지고 요청을 하게되면 IllegalArgumentException
를 대상 객체의 상태가 호출된 메서드를 수행하기 적합하지 않은 경우 illegalStatementException
를 던져 사용할 수 있다. 이런 표준 예외를 사용하면 익숙한 예외이며, 예외 클래스가 적을 수록 메모리 점유도가 낮아지고, 클래스를 적재하는 시간도 줄어들어 효율적인 서비스 운영이 가능하다. 꼭 필요한 경우가 아닌 경우 예외 클래스를 새로 생성하지 말고 표준 예외를 고려해 보면 좋을 것 같다.
이번 예외처리를 읽고 개발하던 코드에 커스텀 예외 클래스를 모두 삭제했다. ㅎㅎ
표준 예외
Exception | usage |
---|---|
IllegalArgumentException | 허용하지 않는 값이 인자로 던져졌을 때 |
IllegalStateException | 객체가 메서드를 수행하기에 적절하지 않은 상태일 때 |
NullPointerException | null을 허용하지 않는 메서드에 null을 건넸을 때 |
IndexOutOfBoundsException | 인덱스가 범위를 넘어섰을 때 |
ConcurrentModificationException | 허용하지 않는 동시 수정이 발견됐을 때 |
UnsupportedOperationException | 호출한 메서드를 지원하지 않을 때 |