❗ 에러(Error) 는 시스템에 무엇인가 비정상적인 상황이 발생한 경우에 사용됩니다.
주로 자바 가상 머신(JVM) 에서 발생시키는 것이며 예외와 반대로 이를 애플리케이션 코드에서 잡으려고 하면 안됩니다.
ex) OutOfMemoryError, ThreadDeath, StackOverflowError
❗ 예외(Exception) 란 개발자의 실수로 예기치 않은 상황이 발생했을 때 입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 어긋나는 경우를 말합니다.
자바에서 예외는 개발자가 직접 처리할 수 있기 때문에 예외 상황을 미리 예측하여 핸들링할 수 있습니다. 예외의 경우 두가지로 나뉩니다.
RuntimeException을 상속하지 않는 클래스는 Checked Exception, 반대로 상속한 클래스는 Unchecked Exception으로 분류할 수 있습니다.
자바에서는 RuntimeExceptoin 및 이를 상속한 클래스를 명시적으로 예외처리를 하지 않아도 되도록 특별 취급 해준다.
❗ 명시적인 예외 처리를 강제하기 때문에 Cheked Exception이라고 한다. 여기서 말하는 명시적인 예외 처리란 try ~ catch로 예외를 잡거나 throw로 호출한 메소드에게 예외를 던지지 않는 행위를 말합니다.
사용되고 있는 예외 처리 몇개만 확인해보자.
다음 예시 코드를 봐보자.
다음과 같이 실행(Runtime)을 하기 이전에 오류를 확인 할 수 있는 것을 볼 수 있습니다.
❗ 명시적인 예외 처리를 강제하지 않기 때문에 Unchecked Exception이라고 합니다. 반드시 try ~ catch로 예외를 잡거나 throw로 호출한 메소드에게 예외를 던져야 합니다.
마찬가지로 사용되고 있는 예외 처리 몇개만 확인해보자.
ArrayIndexOutOfBoundsException: 배열의 범위를 벗어났을 때
NullPointerException: 값이 null이 참조변수를 참조했을 때
만약, 이러한 Exception들의 에러 처리를 강제하게 되면, 리스트에서 값을 꺼내서 사용하거나, 참조하거나 할 때 마다 에러 처리를 해줘야 하기 때문에 강제하지 않습니다.
강제하지 않은 것뿐이지 예외 처리는 가능합니다.
List<String> testList = new ArrayList<>();
testList.add("테스트1");
testList.add("테스트2");
String testStr = testList.get(0);
try {
String testStr = testList.get(0);
catch(ArrayIndexOutOfBoundsException e) {
...
}
다음의 예시도 봐보자.
ArrayList의 배열을 생성하고 각 요소에 들어가 있는 ArrayList를 초기화 시켜주지 않아서 현재 ArrayList[]안의 각 요소는 null인 상태입니다.
따라서, 해당 코드를 실행할 경우 아래와 같이 NullPointerException이 나오는 것입니다.
NullPointerException을 보면 RuntimException을 상속받고 있는 것을 알 수 있습니다.
해당 Exception을 Try-Catch문을 사용해서 잡아보겠습니다.
강제만 하지 않은 것이지 문제 없이 사용할 수 있는 것을 알 수 있습니다.
여기서 트랜잭션 처리는 롤백과 관련해서 Default값임을 명심해야 합니다.
Checked Exception에서도 롤백 처리를 할 수 있습니다.
Checked Exception은 어떻게 예외 처리를 해줘야 하는지 알아볼 것이다.
예외 처리하는 방식에는 세가지 방식이 있습니다.
❗ 예외 상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓는 방법
public sendFile(String fileName)() {
File file;
try {
file = FileFindService.find(fileName);
} catch (FileNotFoundException e){
// 기본 파일을 찾아서 전송한다.
file = FileFindService.find("default.png");
}
send(file);
}
}
대부분의 상황에서 예외를 복구할 수 있는 경우는 거의 없기 때문에 자주 사용되지 않는다. 예를 들어, 유니크해야 하는 이메일값이 중복되어 SQLException이 발생한다고 해도 복구할수 있는 방법이 없다. 이런 경우에는 RuntimeException을 발생시키고 입력을 다시 유도하는 것이 현실적이다.
혹시나 예외 복구를 사용할 일이 생긴다면 위처럼 예외를 복구하는 방식보다는 아래처럼 코드의 흐름을 제어하는 것이 좋다.
public void sendFile(String fileName){
if(FileFindService.existed(filename)){
// 파일이 있는 경우 해당 파일을 찾아서 전송한다.
send(FileFindService.find(fileName));
}else{
// 파일이 없는 경우 기본 이미지를 전송한다.
send(FileFindService.find("default.png"));
}
}
❗ 예외 처리를 직접 담당하지 않고 호출한 쪽으로 던져 회피하는 방법
// 예시 1
public void add() throws SQLException {
// ...생략
}
// 예시 2
public void add() throws SQLException {
try {
// ... 생략
} catch(SQLException e) {
// 로그를 출력하고 다시 날린다!
throw e;
}
}
❗ 예외 회피와 비슷하게 메서드 밖으로 예외를 던지지만, 그냥 던지지 않고 적절한 예외로 전환해서 넘기는 방법
// 조금 더 명확한 예외로 던진다.
public void add(User user) throws DuplicateUserIdException, SQLException {
try {
// ...생략
} catch(SQLException e) {
if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
throw DuplicateUserIdException();
}
else throw e;
}
}
// 예외를 단순하게 포장한다.
public void someMethod() {
try {
// ...생략
}
catch(NamingException ne) {
throw new EJBException(ne);
}
catch(SQLException se) {
throw new EJBException(se);
}
catch(RemoteException re) {
throw new EJBException(re);
}
}
다른 코드도 확인해 보자.
public Object method() {
try {
...
} catch (IOException e) {
throw new CustomException ("IOException 발생");
}
}
public class CustomException extends RuntimeException{
public CustomException(String message) {
super(message);
}
}
보통 예외 처리를 하기 위해서 위와 같이 RuntimeException을 상속 받은 클래스로 전환하여 던집니다.
✅ 예외 복구 전략이 명확하고 복구가 가능하면 Checked Exception을 try-catch로 잡아서 예외 복구를 하거나, 코드의 흐름으로 제어하는 것이 좋다.
✅ 그러나 이러한 경우는 흔하지 않기 때문에 Checked Exception이 발생하면 더 구체적인 UnChecked Exception을 발생시키고 예외에 대한 메시지를 명확하게 전달하는 것이 효과적이다.
✅ 무책임하게 상위 메서드에 throw로 예외를 던지는 행위를 하지 않는 것이 좋다. 상위 메서드들의 책임이 그만큼 증가하기 때문이다.
✅ Checked Exception은 기본 트랜잭션 속성에서 Rollback을 진행하지 않는다.
❗ 에러(Error)란?
에러(Error)는 시스템에 무엇인가 비정상적인 상황이 발생한 경우에 사용됩니다. 주로 자바 가상 머신에서 발생시키는 것이며 예외와 반대로 이를 애플리케이션 코드에서 잡을 수 없다.
❗ 예외(Exception)란?
예외(Exception)란 입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 어긋나는 것을 말합니다. 자바에서 예외는 개발자가 직접 처리할 수 있기 때문에 예외 상황을 미리 예측하여 핸들링할 수 있다.
❗ Checked Exception에 대해 설명하라
Checked Exception은 RuntimeException을 상속하지 않은 클래스이며, 명시적인 예외 처리를 해야 한다. 컴파일 시점에 확인할 수 있고 트랜잭션 안에서 동작할 때 Checked Exception이 발생하면 롤백되지 않는 특징이 있다.
❗ UnChecked Exception에 대해 설명하라
UnChecked Exception은 RuntimeException을 상속한 클래스이며, 명시적인 예외 처리를 하지 않는다. 런타임 시점에 확인할 수 있고 트랜잭션 안에서 동작할 때 UnChecked Exception이 발생하면 롤백된다는 특징이 있다.
❗ 예외(Checked Exception)를 처리하는 방식에 대해 설명하라
예외 상황을 파악하고 문제를 해결해서 정상 상태로 복구하는 예외 복구 방식, 예외 처리를 직접 담당하지 않고 호출한 쪽으로 넘기는 예외 처리 회피, 적절한 예외로 전환해서 넘기는 예외 전환 방식이 있다.
❗ 올바른 예외 처리 방식
예외 복구 전략이 명확하고 복구가 가능하다면 Checked Exception을 try-catch로 잡아서 예외를 복구하는 것이 좋다. 복구가 불가능한 Checked Exception이 발생하면 더 구체적인 UnChecked Exception을 발생시키고 예외에 대한 메시지를 명확하게 전달하는 것이 좋다. 무책임하게 상위 메서드에 throw로 예외를 던지는 것은 상위 메서드의 책임이 증가하기 때문에 좋지 않은 방법이다.
Reference