Error vs Exception
- Error 란?
- Error(오류)는 시스템에 비정상적인 상황이 생겼을 때 발생한다.
- 시스템 레벨에서 발생하기 때문에 심각한 수준의 오류이고, 개발자가 미리 예측하여 처리하기 힘들다.
- 그렇기 때문에 애플리케이션에서 오류에 대한 처리를 거의 신경 쓰지 않아도 된다.
- 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 블록은 필수 블록이 아닙니다
// 무조건 실행됩니다. 그래서 항상 수행해야 할 필요가 있는 코드를 넣습니다
}
throws - 간접 처리 방식
- 방법 1
void innerMethod() throws UnCheckedException {
UnCheckedException uce = new UnCheckedException();
uce.unCheckedException(); // Exception 발생
}
public static void main(String[] args) {
try{
innerMethod(); // 메서드 호출
} catch(UnCheckedException ex){
System.err.println(e);
}
}
- 위와 같이 코드가 있는 메서드를 호출하는 곳으로 예외 처리의 책임을 넘깁니다.
- 방법 2
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("예외가 발생했습니다...");
}
}
}
- 로직상에 Exception 처리와는 관련 없지만, 예외를 발생시키는 방법: throw
예외 처리 방법
예외 복구
public static void main(String[] args) throws IOException {
byte[] list = {'a', 'b', 'c'};
try {
System.out.write(list);
} catch (IOException e) {
log.info(e);
}
}
- 예외 복구 방법은 대부분의 상황에서 예외를 복구할 수 없기에 실무에서는 보통 잘 사용할 일이 없다.
예외 처리 회피
public static void main(String[] args) throws IOException {
byte[] list = {'a', 'b', 'c'};
System.out.write(list[4]);
}
- 예외 처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던져버리는 방법 ( throws )으로 위와 같은 코드로 예외를 던져버린다.
- 적당한 상황에서 사용하면 퀄리티 좋은 코드가 나오지만 무분별하게 사용하게 된다면 코드의 퀄리티가 떨어지기에 추천하는 방법은 아니다.
예외 전환 (추천)
public static void main(String[] args) {
byte[] list = {'a', 'b', 'c'};
try {
System.out.write(list);
} catch (IOException e) {
throw new RuntimeException("list를 읽지 못했습니다.");
}
}
- 예외를 적절한 예외로 전환해서 자신을 호출할 쪽으로 던져버리는 방법으로 아래와 같은 방법으로 예외를 전환시킨다.
public class CustomException extends RuntimeException{
public CustomException(String message) {
super(message);
}
}
- 보통 실무에서는 예외 처리를 하기 위해서 위와 같은 방법으로 RuntimeException을 상속받은 클래스를 만들어서 예외 전환 방법으로 예외를 처리한다.
REFERENCES
'Java' 카테고리의 다른 글
Stream (0) | 2022.02.26 |
---|---|
Static 변수와 Static 메서드 (0) | 2022.02.26 |
Optional (0) | 2022.02.26 |
Object 클래스 (0) | 2022.02.26 |
Class 클래스 (0) | 2022.02.26 |