[Java] Exception Handling(복구, 회피, 전환)

#import

Java 예외 처리(Handling Exception)에 대해[Nesoy Blog - Que Sera Sera]
Java 예외(Exception) 처리에 대한 작은 생각(NEXTREE.IO)


Exception Handling

최근 Exception을 Handling 하면서 세부적인 Handling 기법들에 대해 고심하지 않고,

Handling 하다보니 명확한 기준을 잡으며 처리하기 힘들었다.

이번 gillogException Handling에 대해 조금 더 알아보려 한다.


먼저 Error, Exception, Checked, UnChecked에 대한 선행 정리 내용을 숙지한 상태로 시작해보려 한다.

아래 Exception Handling 관련 내용은,

UnCheckedException, RuntimeException 관련 Exception Hadnling 기법들이다.


1. 예외 복구

예외 복구의 핵심Exception이 발생하여도 Application은 정상적으로 동작한 다는 것이다.

Exception 발생 시 이를 예측하여 다른 비즈니스 로직 흐름으로 유도 시키거나,

예외가 발생하지 않는 상황으로 복구를 시도하는 로직을 추가하는 방식이다.

아래 코드를 살펴보자.

private void mayThrowExceptionLogic() {
    int maxTry = 20;
    while(maxTry --> 0) {
    	try {
    		// ???Exception 이 Throw 될 수 가능성이 있는 로직
        
        	// 성공 시 return, 해당 메소드 종료
        	return ;
    	} catch(???Exception e) {
    		// Error 로그 출력
                // 실패 로직 존재 시 원상 복구
        	// 일정 시간 동안 대기
    	} finally {
    		// 작업에 사용한 Resource 반환 및 정리
    	}
    }
    // 최대 횟수 실패시 예외 Throw
    throw new MaxTryFailedException();
}

만약 서버 상태에 따라 접속 불안정 등으로 실패 가능성이 있는 로직에,

maxTry 만큼 정상 로직을 재시도하여 maxTry가 초과될 경우 또 다른 Exception으로 전환하여 Throw 한다.

maxTry의 시도비즈니스 로직이 정상 수행 될 수 있고,

throw new MaxTryFailedException();와 같이 새로운 Exception으로 전환하여 Throw 하지 않더라도,

해당 로직 실패다른 수행 로직을 첨가하여 Application의 흐름을 정상적으로 마무리할 수도 있다.


2. 예외 회피

private void mayThrowExceptionLogic() throws ???Exception {
	// 비즈니스 로직
}

위와 같은 코드를 많이 사용하고 있지만 아주 신중히 생각해야 한다.

Exception 발생 시 throws를 통해 호출 된 부분으로 해당 Exception을 던져버리고,

Exception Handling을 회피하는 방식이다.

해당 방식호출 부분에서 Exception을 Handling 하는 것이 더 바람직 하거나,

해당 로직에서 처리하지않고 Exception을 회피하고 throw 하는 것에 확신이 들 경우만 사용해야 한다.


3. 예외 전환

try {
	// Exception 발생 가능 로직
}
catch(???Exception e) {
	// Exception 로깅
    	// 복구 로직
        throw CustomSpecificExceptionJustLikeNotAllowedUserException("이런상황~");
}

예외 전환 방식위 코드와 같이 특정 Exception 발생 시 새로운 Exception으로 전환하여,

호출 부분으로 throw 하여 호출 부분에서 Exception을 Handling 할 때,

어떤 Exception인지 더욱 분명히하여 해당 Exception에 대한 Handling을 더욱 수월히 하는 방식이다.


CheckedException 처럼 복구 불가능 Exception을 catch 하여,

UncheckedException 으로 전환하여 Handling 함으로 써,

다른 계층에서 CheckedException을 일일히 선언하지 않아도 되게 할 수도 있다.


공통 중요사항

Exception을 Handling 할 때 중요한 사항들이 있는데 아래와 같다.

catch에는 로깅, 복구 등의 로직을 추가하기

try {
	// Exception 발생 가능 로직
} catch(???Exception e) {
}

위 코드와 같이 Exception을 catch한 후에 아무 로직 없이 catch만 하는 것은 적합하지 않다.

Log를 출력하거나, 해당 Exception 발생 로직을 원상 복구 시키는 로직을 첨가하는 등,

catch만 수행하지 않고 해당 Exception에 대한 처리를 해주어야 한다.


catch에 단순히 throw만 하지 않기

try {
	// Exception 발생 가능 로직
} catch(???Exception e) {
	throw e;
}

위 경우와 마찬가지로 Log나 적절한 로직을 추가하여야 하고,

단순히 catch 후에 throw시키는 것은 적합하지 않다.


e.printStackTrace() X, Logging Framework 사용

try {
      // Exception 발생 가능 로직
} catch (IOException e) {
      e.printStackTrace()
}

Tomcat에서 e.printStackTrace()로 Console에 찍히는 log는,

{TOMCAT_HOME}/logs/catalina.out 에만 저장된다.

Logging Framework를 이용하면 파일을 쪼개는 정책을 설정할 수 있고,

여러 Server의 log를 한곳에서 모아서 보는 System을 활용할 수도 있다.

e.printStackTrace() 대신 LoggingFramwork를 활용하자.
slf4j, commons logging, log4j, logback ...


Exception Stack을 남겨 추적, 유지보수성 높이기

Exception의 추적성과 유지보수 성을 높이기 위해서,

e.toString()이나 e.getMessage()로 마지막 Exception Message만 남기기보다,

전체 Exception Stack을 다 넘기는 편이 좋다.
대표적인 slf4j의 log.error() 역시 e.printStackTrace()처럼 Exception의 stack도 남긴다.


위에서 정리한 Exception Handling 기법들을 고려하여 조금 더 세심한 Handling을 해보자.

좋은 웹페이지 즐겨찾기