시스템 레벨에서 발생하기 때문에 심각한 수준의 오류이고, 개발자가 미리 예측하여 처리하기 힘들다.
그렇기 때문에 애플리케이션에서 오류에 대한 처리를 거의 신경 쓰지 않아도 된다.
Exception 이란?
개발자가 구현한 로직에서 발생한다.
예외는 발생할 상황을 미리 예측해서 처리할 수 있다.
그렇기 때문에 예외를 구분하고 그에 때른 처리 방법을 명확히 알고 적용하는 것이 중요하다.
크게 RuntimeException 과 그 밖에 여러 Exception으로 구분된다.
RuntimeException 의 종류는 아래와 같다.
ArithmeticException : 정수를 0으로 나누었을 경우
ArrayStoreException : 배열 유형이 허락하지 않는 객체를 배열에 저장하려는 경우
ArrayIndexOutOfBoundsException : 배열을 참조하는 인덱스가 잘못된 경우
ClassCastException : 적절치 못하게 Class를 형 변환하는 경우
NullPointerException : 널 객체를 참조했을 경우
NegativeArraySizeException : 배열의 크기가 음수인 경우
NoClassDefFoundException : 클래스를 찾을 수 없는 경우
OutOfMemoryException : 사용 가능한 메모리가 없는 경우
IndexOutOfBoundsException : 객체의 범위를 벗어난 index를 사용하는 경우
IllegalArgumentException : 메소드 유형이 일치하지 않는 매개변수를 전달하는 경우
IllegalMonitorStateException : 스레드가 스레드에 속하지 않는 객체를 모니터 하려고 기다리는 경우
IllegalStateException : 적절하지 않는 때에 메소드를 호출하는 경우
예외클래스
위의 그림은 예외클래스의 구조이다.
모든 예외클래스는 Throwable 클래스를 상속받고 있고, Throwable은 Object의 자식클래스다.
Error 와 Exception은 Throwable을 상속받고 있다.
여기서 RuntimeException을 주목할 필요가 있는데, RuntimeException는 UnCheckedException이다.
Error 와 RuntimeExcption은 UnCheckedException 에 속한다.
RuntimeExcption 를 제외한 Exception은 CheckedException 에 속한다.
Checked Exception VS Unchecked Exception
Checked Exception과 Uncheckd Exception을 구분하는 기준은 '꼭 처리를 해야 하느냐" 이다.
Checked Exception은 컴파일단계에서 확인이 가능하고, Unchecked Exception은 실행단계에서 확인이 가능하다.
Checked Exception이 발생할 수 있는 메소드는 반드시 try/catch로 감싸거나 Throw를 던져야 한다.
Unchecked Exception 는 명시적으로 예외를 처리하지 않아도 된다.
그렇기 때문에 개발자가 부주의해서 발생하는 경우가 많다.
Exception 과 roll-back 관계
개발자는 예외발생시 트랜잭션의 roll-back 여부를 인지하고 있어야한다.
그 이유는 roll-back 이 되는 범위가 달라지기 때문에 개발자가 이를 인지하지 못하면 예상하지 못한 예외가 발생할 수 있기 때문이다.
Checked Exception 는 예외가 발생하면 트랜잭션을 roll-back하지 않고 예외를 던진다.
Unchecked Exception 은 예외 발생 시 트랜잭션을 roll-back한다는 점에서 차이가 있다.
그렇기 때문에 트랜잭션의 전파방식(propagation behavior)과 트랜잭션을 어떻게 묶어놓느냐에 따라서 Exception의 영향도가 커진다.
그러므로 전파방식(propagation behavior)과 roll-back 규칙을 적절하게 설정하면 효율적으로 애플리케이션을 구현할 수 있다.
아래와 같이 @Transactional의 rollbackFor 옵션을 이용하면 Rollback이 되는 클래스를 지정할 수 있다.
// Exception예외로 롤백을 하려면 다음과 같이 지정
@Transactional(rollbackFor = Exception.class)
// 여러개의 예외를 지정
@Transactional(rollbackFro = {RuntimeException.class, Exception.class})
//예외가 발생하면 롤백이 되지 않도록 지정
@Transactional(noRollbackFor={IgnoreRollbackException.class})
예외 처리 방식
try catch finally - 직접 처리 방식
try{
// 예외 발생 가능성이 있는 코드
// 예외가 발생하면 try 블록의 나머지 문장들은 수행되지 않습니다.
} catch{
// 최소 하나의 catch 블록
// Exception은 java.lang.Throwable 클래스의 하위 클래스 타입으로 선언되어야 합니다.
// try 블록 안에서 발생한 예외와 동일한 예외 타입 catch 블록을 수행합니다.
// 보통 catch 문 안에는 로직을 넣지 않습니다. log만 찍고 끝냅니다.
// catch 블록이 여러 개로 구성될 때, 계층구조가 높을수록 아래로 내려갑니다. 즉, 자식 Exception부터 아래로 구성합니다.
// 부모 Exception부터 Catch 블록이 구성되면 UnReachableException이 발생합니다.
} finally{
// finally 블록은 필수 블록이 아닙니다
// 무조건 실행됩니다. 그래서 항상 수행해야 할 필요가 있는 코드를 넣습니다
}
public class Main {
public static void throwExample() throws Exception {
throw new Exception();
}
public static void main(String[] args) {
try {
throw new Exception();
} catch (Exception e){
System.out.println("예외가 발생했습니다...");
}
}
}