본문 바로가기

개발노트/SPRING

JAVA 예외(Exception) 과 예외 처리

예외 (Exception)는 개발자가 구현한 로직에서 발생합니다.

그렇기 때문에 에러 (Error) 와 달리 상황을 미리 예측하여 처리할 수 있습니다.

따라서 이러한 예외를 구분하고 그에 따라 명확하게 처리 하는것 이 중요합니다.

 

1. 예외 클래스

[그림1] 출처: https://howtodoinjava.com/best-practices/java-exception-handling-best-practices/

 

위 [그림1]은 예외클래스의 구조입니다.

Exception 과 Error 클래스가 Throwable 클래스를 상속받고 있습니다.

 

Error 는 시스템 레벨에서 비정상적인 상황이 생겼을때 발생하기 때문에 개발자가 미리 예측할 수 도 없고 처리할수도 없습니다. 따라서 애플리케이션에서 개발자가 Error 에 대한 처리를 신경 쓰지 않아도 됩니다.

 

반면, Exception 은 개발자가 직접 처리를 할 수 있습니다.

 

2. Checked Exception 과 Unchecked Exception 

  Checked Exception Unchecked Exception
처리 여부 반드시 예외 처리 해야함 명시적인 예외 처리 하지 않아도 됨
확인시점 컴파일 단계 실행단계
예외발생시 트랜잭션 처리 roll-back 하지 않음 roll-back 함
대표 Exception

Exception 의 상속받는 하위 클래스 중 Runtime Exception 을 제외한 모든 예외

IOException

SQLException

ClassNotFoundException ...

Runtime Exception 하위 예외

NullPointerException

SystemException ...

 

예외처리 여부

Checked Exception 과 Unchecked Exception 의 가장 구분점은 예외 발생상황에서 처리유무 입니다.

 

Checked Exception 은 컴파일 단계에서 명확하게 Exception 체크가 가능하여 try/catch 로 감싸거나 throws 로 던지지 않으면 컴파일 에러가 발생 합니다. 

반대로 Unchecked Exception 은 실행과정 중 발생되는 예외로 컴파일 단계에서 확인 할 수 없고, 실행과정중에 발생 된다 하여 Runtime Exception 이라 합니다.

 

Rollback 여부

기본적으로 Checked Exception 은 예외가 발생하면 트랜잭션을 rollback 하지 않고, Unchecked Exception 은 예외 발생 시 rollback 처리 합니다.

따라서 개발자가 이를 인지하지 못하고 Checked Exception 상황에서 무분별한 throws 및 적절하지 못한 예외 처리를 한다면, 심각한 시스템 결함을 초래 할 수 있습니다.

 

3. Chedked Exception 예외 처리 전략

3-1. 예외 복구

예외를 try/catch 로 잡아서 적절한 처리를 하여 다른 작업흐름으로 유도 합니다.

예외복구는 예외가 발생하여도 애플리케이션은 정상적인 흐름으로 진행되어야 할때 사용하는 전략 입니다.

 

try {
    process();
} catch (IOException e) { // Better Code
    log.error("Service Layer IOException {}", e.getMessage(), e);
    throw e
}

 

3-2. 예외처리 회피

예외가 발생하면 throws 를 통해 호출한쪽으로 예외를 던지고 처리를 회피합니다.

이 전략은 명확하게 호출한 곳에서 처리하는 것이 최선이라는 확신이 있을때만 사용해야 합니다.

public void updateUser throws NullPointerException {

    ....
}

 

3-3. 예외 전환

try/catch 문에서 예외를 잡아서 다른 예외를 던지는 방법입니다.

Checked Exception 중 복구가 불가능한 예외가 잡혔다면 이를 Unchecked Exception 으로 전환하여 다른 계층에서 일일이 예외를 선언할 필요가 없도록 하기 위함입니다.

 

private void registStartAuctionJob(String rfxId, Date rfxStartDt, Object[] args) {
	try {
		scheduleService.registSchedule(
				Class.forName(AuctionJobConst.AUCTION_SERVICE_CLASS_NAME),
				AuctionJobConst.AUCTION_START_METHOD_NAME,
				args,
				rfxStartDt,
				AuctionJobConst.AUCTION_JOB_GROUP,
				rfxId,
				AuctionJobConst.AUCTION_START_JOB_NAME,
				null);
	} catch (ClassNotFoundException e) {
		throw new CommonException(ErrorCode.FAIL, e);
	}
}

 

 

 

일반적인 웹 애플리케이션이라면..

웹 애플리케이션 특성상 Checked Exception 일 경우라도 복구 할 수 없고, 원복해야하는 프로세스가 대부분 입니다. 또한 throws 하더라도 호출하는 쪽에서 별도로 처리 할 수 있는게 없기 때문에

예외 복구 나 예외 처리 회피가 무의미해지는 경우가 많습니다.

 

가능한 빨리 이를 RuntimeException 으로 포장하여, 무차별 throws 를 선언하지 않도록 해주는 것이 좋습니다.

 

 

'개발노트 > SPRING' 카테고리의 다른 글

Gson 직렬화 시 Null object field 처리  (0) 2020.03.25