자바 예외 (exception)

이성훈·2025년 4월 10일
post-thumbnail

자바 예외에 대해 학습하고 정리한 내용입니다.

예외 계층

예외도 객체이기에 Object가 최상위 부모입니다.

Throwable 최상위 예외

이 클래스(또는 그 하위 클래스 중 하나)의 인스턴스인 객체만 Java 가상 머신에서 throw되거나 Java throw 문에서 throw될 수 있습니다.
마찬가지로, 이 클래스 또는 그 하위 클래스 중 하나만 catch 절의 인수 유형이 될 수 있습니다.

Error (시스템 오류)

Error 메모리 부족, 심각한 시스템 오류

→ 애플리케이션에서 복구 불가능한 시스템 예외
	⇒ 애플리케이션 개발자는 이 예외를 잡으려고 해서는 안됩니다.
  • 상위 예외를 catch로 잡으면 그 하위 예외까지 잡습니다.
    따라서 애플리케이션 로직에서는 Exception 부터 필요한 예외로 생각하고 잡으면 됩니다.

예외 기본 규칙

  1. 예외는 잡아서 처리하거나, 던져야 한다.
  2. 잡거나 던질 때 지정한 예외 뿐만 아니라 그 예외의 자식들도 함께 처리 된다.
    • Exceptioncatch로 잡으면 하위 예외들도 모두 잡을 수 있음
    • Exceptionthrow로 던지면 하위 예외들도 모두 던질 수 있음

Exception: 체크 예외

  • 애플리케이션 로직에서 사용할 수 있는 실질적인 최상위 예외입니다.
  • Exception의 하위에 존재하지만 RuntimeException은 예외로 언체크 예외입니다.

RuntimeException: 언체크 예외 (런타임 예외라고도 부름)

  • 컴파일러가 체크하지 않습니다.

⭐ Checked Exception
반드시 처리해야 하고, 처리하지 않으면 컴파일 에러가 발생해서 컴파일되지 않음

⭐ Unchecked Exception
처리하지 않아도 컴파일 에러가 발생하지 않고, 실행이 가능

Checked Exception

잡아서 처리하거나, 밖으로 던지도록 선언해야 함 그렇지 않으면 컴파일 오류 발생합니다.

체크 예외를 처리할 수 없을 때는 method() throws예외 를 사용해서 밖으로 던질 예외를 필수로 지정해 주어야 합니다.

throws에 상위 타입을 주어도 던질 수 있습니다.

장점

개발자가 실수로 예외를 누락하지 않도록 컴파일러를 통해 문제를 잡아줍니다.

단점

개발자가 모든 체크 예외를 반드시 잡거나 던지도록 처리해야 하기 때문에, 크게 신경쓰고 싶지 않은 예외까지 모두 챙겨야 합니다.

+) 의존관계에 따른 단점까지 존재합니다.


Unchecked Exception

  • RuntimeException 과 그 하위 예외
  • 컴파일러가 예외를 체크하지 않습니다.

예외를 잡아서 처리하지 않아도 throw 를 생략할 수 있습니다.

장점

신경쓰고 싶지 않은 예외를 무시할 수 있으며, 의존관계를 참조하지 않아도 됩니다.

단점

개발자가 실수로 예외를 누락할 수 있습니다.

예외 활용

  1. 기본적으로 언체크(런타임) 예외를 사용하자

  2. 체크 예외비즈니스 로직상 의도적으로 던지는 예외에만 사용하자

    ex) 계좌 이체 실패, 결제시 포인트 부족, 로그인 ID or PW 불일치 등… 
        개발자가 실수로 예외를 놓치면 안된다고 판단되는 경우

체크 예외의 문제점

  1. 복구 불가능한 예외
    • 대부분의 예외는 복구가 불가능 따라서 공통으로 처리하고 해당 문제는 개발자가 해당 오류를 빠르게 인지하는 것이 필요합니다.
  2. 의존 관계에 대한 문제
    • 컨트롤러나 서비스 입장에서 처리할 수 없어도 throws를 통해 선언되어야 합니다.
      이에 따라 예외를 의존하게 되고, 다른 기술로 변경되었을 때, 코드 변경이 필요하게 됩니다.

💡 throws Exception을 사용하면 해결이 가능
하지만, 다른 체크 예외를 체크할 수 있는 기능이 무효화되고,
중요한 예외가 발생해도 놓치게 됨
따라서 꼭 필요하지 않다면 Exception을 밖으로 던지는 것은 좋지 않은 방법

언체크 예외 활용

  • 시스템에서 발생한 예외는 대부분 복구 불가능 예외이기에 서비스나 컨트롤러에서 신경쓰지 않고, 일관성 있게 공통으로 처리하는 것이 좋습니다.
  • 해당 객체가 처리할 수 없는 예외는 무시 → 체크 예외처럼 강제로 의존 X

예외 전환

체크 예외가 발생하면 런타임 예외로 전환해서 예외를 던지고,

  • 이때 기존 예외를 포함해 주어야 출력 시 스택 트레이스에 기존 예외도 함께 확인 가능합니다.

런타임 예외는 놓칠 수 있기 때문에 문서화가 중요합니다.

  • 문서화
  • 코드에 throws 런타임예외를 남겨서 중요한 예외를 인지할 수 있게 하는 것도 방법입니다.


예외를 전환할 때는 기존 예외를 포함해야 한다

catch(SQLException e) {
	throw new runtimeSQLException(e);
}
  • 포함하지 않을 경우 기존에 발생한 예외를 식별할 수 없습니다.
    ex) SQLException일 경우 DB에서 발생한 예외를 확인할 수 없는 문제가 생기게 됩니다.



@Slf4j
public class Exam {
	public void exam() {
    	try{ 
        	// ... 
        } catch(Exception e) {        
    		log.info("message={}", msg, e);
        }
    }
}

+) 로그를 출력할 때 마지막 파라미터에 예외를 넣어주면 로그에 스택 트레이스를 출력할 수 있습니다.

INFO  ... message=데이터 저장 실패
java.lang.IllegalArgumentException: 잘못된 인자입니다.
    at com.example.Exam.exam(Exam.java:42)
    ... (이하 생략된 스택트레이스)
profile
느려도 단단하게

0개의 댓글