들어가며
나는 지금까지 예외처리에 대해서 깊게 생각해 본적이 없는 것 같다. 단순하게 ‘문제가 생기면 예외를 던진다.’ 라고 생각하며 살아왔던 것 같다. 하지만 우테코에서 예외처리 강의를 듣고 한번 생각 정리를 할 필요가 있을 것 같아서 정리해보게 되었다.
예외(Exception) 와 에러(Error)
예외를 알아보기 전에 먼저 에러와 예외를 구분할 필요가있다.
에러는 코드로 복구 될 수 없는 오류를 의미한다. 개발자가 미리 예측하여 방지할 수 없다.
OutOfMemoryError, StackOverflowError 등이 발생한다.
예외는 개발자가 직접 예측하여 막을 수 있는 오류를 의미한다. 개발자의 코드, 로직, 사용자 에 의해 발생 가능하며 방지할 수 있다.
하단 그림은 에러와 예외의 상속 관계이다.
Exception 상속 구조
예외와 에러는 모두 Throwable을 상속받는다.
Throwable 객체는 예외와 에러에 대한 메세지를 담고, 연결된 예외와 에러에 대한 정보를 담는다. 흔히 우리가 사용하는 getMessage()
, printStackTrace()
메소드로 구현되어있다. 이를 우리는 상속받는 Error, Exception에서 사용하는 것이다.
프로그램 예외
컴파일 에러
컴파일 에러는 컴파일 단계에서 오류 발생시 컴파일러에서 에러메세지를 호출해 주는 것을 의미한다. 개발자가 코드를 작성함에 있어서 실수가 생길 경우 컴파일 에러를 일으킨다.
Checked Exception 이라고도 한다. 문제에 대해 먼저 체크를 하고 실행여부를 판단하기 때문이다.
Ex) 미사일은 북한만 보낼수있는데 만약 개발자가 일본으로보낸다면 ? → 개발자가 의도치 않게 코딩 못하도록 막는 것이다.
필자 생각은 checked exception을 따로 처리해 줄 필요가 있을까 싶다. 개발자가 코드를 잘 작성하면 된다고 생각한다. 반면에 코드의 양이 많아지면 다른 개발자들에게 제약을 줌으로써 해결할 수도 있을 것 같기도 하고, 잘 모르겠다.
런타임 에러
프로그램 실행 중 에러가 발생해서 잘못된 결과, 예상치 못한 문제로 인해 프로그램이 비정상적으로 종료 될 경우를 의미한다.
Unchecked Exception 이라고도 한다. 문제에 대해 체크를 하지 않고 실행하기 때문이다.
💡 우리가 항상 말하는 것은 컴파일 에러, 런타임 에러였다. 그래서 ‘컴파일 에러가 위에서 말한 에러면 코드로 복구될수 없는건가?’ 라고 생각해보기도 했다. 하지만 자바는 에러를 에러와 예외로 나누는데 여기서 컴파일 에러, 런타임 에러들은 예외로 빠진다.
Checked Exception 과 Unchecked Exception은 언제 사용해야 할까 ?
호출하는 메소드가 Exception을 활용해 무엇인가 의미 있는 작업을 할 수 있다면 Checked Exception을 사용하는 것이 좋다. 예외 처리에 대한 책임을 확실하게 넘길 수 있기 때문이다.
만약 호출하는 메소드가 Exception을 catch해 예외 상황을 해결하거나 문제를 해결할 수 없다면 Unchecked Exception을 사용하라. 개발자나 사용자가 에러를 처리할 수 있도록 하는 것이다.
명확하지 않다면 Unchecked Exception을 사용하라.
Checked Exception을 사용한다면 throws를 이용해 호출된 메소드에서 호출하는 메소드로 예외를 던진다고 할 수 있다. 계속해서 throw 되어지는 예외는 가독성을 떨어뜨리고 어디서 예외가 발생했는지 모르게한다. 이럴 경우 throws를 이용해 처리하는 예외를 Unchecked Exception을 통해 처리 할 수도 있다. 그래서 처리하는 쪽에 달려있다.
예외를 처리하는 방법
try-catch
밑에 코드와 같은 방식으로 try-catch-finally 키워드를 통해 예외를 처리할 수 있다.
try : 이블록에서 예외가 발생할 만한 코드
catch : 예외 발생시 처리할 동작
try {
return new Names(inputView.readPlayerNames());
} catch (Exception e) {
System.out.println(e.getMessage());
return setNames();
}
throws
예외를 던지는 것이다. 예외를 여기서 처리 안하며 메소드를 호출한 메소드에게 에러 처리 책임을 떠 넘기는 것이다.
public static void divide(int a,int b) throws ArithmeticException {
if(b==0) throw new ArithmeticException("0으로 나눌수 없다.");
System.out.println(a/b);
}
Exception 관련 알아야할 내용
- 메소드에서 쉼표(,)를 통해 여러개의 exception을 throws 할 수 있다.
- 여러개의 exception 일경우 throws Exception을 통해 처리 가능하다.
- try-catch문에서 여러개의 exception catch문을 사용하여 처리할 수 있다.
- 예외를 처리하고 예외를 재throw 하는 것이 가능하다.
- StackTrace를 사용하여 예외가 발생한 원인을 찾기 위해 발생 경로를 추적하는 것이 가능하다.
예외처리 활용
복구
예외가 발생한 문제를 정상 상태로 돌리는데 사용된다. 재처리 또한 복구에 해당한다.
회피
직접 예외를 처리하징않고 호출한 쪽으로 회피한다.
무시
예외를 무시한다.
전환
Checked Exception을 Unchecked Exception으로 전환할 수 있다.
Checked Exception을 사용하는 경우와 Unchecked Exception을 사용하는 자신만의 원칙은 무엇인가?
따로 정해진 것은 없지만, Checked Exception 같은 경우에는 코드적으로 제약을 줌으로써 안정성을 높일 수 있다. 그래서 협업과정에서 코드에 제약을 줄 필요가 있을 경우 사용할 것 같다.
UncheckedException은 런타임 에러가 날 경우 자주 사용할 것 같다.
자주 사용되는 예외
IllegalArgumentException
- 호출자가 인수로 부적절한 값을 넘길 때 사용한다.
IllegalStateException
- 대상 객체의 상태가 호출된 메서드를 수행하기에 적합하지 않을 때 사용된다.
NullPointerException
- null 값을 허용하지 않는 메서드에 null 값을 전달할 때 사용된다.
IndexOutOfBountException
- 인덱스가 범위를 넘어섰을 때 사용되어진다.
UnsupportedOperationException
- 호출한 메서드를 지원하지 않을 때 사용한다.
나가며
난 예외처리에 대해 아무것도 몰랐다. 이번에 알았다. 한줄한줄 예외처리문을 작성할 때 생각하며 작성해야겠다.
그리고 다른 크루들이 사용하는 커스텀 예외에 대해서도 한번 알아봐야겠다.
'코코코딩공부 > JAVA' 카테고리의 다른 글
[JAVA] VO(Value Object) 란 무엇인가 ? (0) | 2023.03.12 |
---|---|
[JAVA] 제네릭 Generic (1) | 2023.03.04 |
[JAVA] 일급 컬렉션 (0) | 2023.02.25 |
[JAVA] 원시값 포장 (0) | 2023.02.25 |
[JAVA] equals와 hashCode를 Override 해야하는 이유 (0) | 2023.02.25 |