목표
자바의 예외 처리에 대해 학습하세요.
학습할 것 (필수)
- 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
- 자바가 제공하는 예외 계층 구조
- Exception과 Error의 차이는?
- RuntimeException과 RE가 아닌 것의 차이는?
- 커스텀한 예외 만드는 방법
오류의 종류
일단 프로그램 오류의 종류는 다음과 같이 3가지로 분류가 된다.
1. 컴파일 에러
-> 구문 에러라고 볼 수 있는데 프로그램이 시작 전에 잡을 수 있는 에러라고 보면 된다.
2. 런타임 에러
-> 프로그램 실행 중에 나타나는 에러로 대체로 Null point error , 0으로 나누기를 실행하는 경우가 있다.
3. 논리적 에러
-> 프로그램이 원하는 기댓값이 나오지 않는 경우 즉 프로그래머가 잘못한 경우가 거의 99.9%
자바가 제공하는 예외 계층 구조
자바의 예외 계층 구조는 다음 그림과 같다.
출처: online.infomatics.info/Course/Core-Java/Types-of-Exception
Throwable Class의 서브 클래스 인 Exception과 Error로 나뉩니다.
여기서 좀 더 자세히 알아보자면
Throwable
-> 자바에서 예외처리를 하기 위한 최상위 클래스이며 이 클래스를 상속받은 서브클래스 만이 thows 키워드를 통해
전파될 수 있습니다.
Error
-> 동적 연결 실패 또는 다른 심각한 오류가 자바 가상 머신(JVM)에서 발생했을 때 발생하는 오류임으로 대부분 JVM에서 발생하는 오류들이다. (예시 예외는 예외 계층구조 그림에 있습니다.)
Exception
-> 런타임과 컴파일 시간에 발생할 수 있는 예외를 잡기 위한 예외 클래스(?) 주로 개발자가 작성한 코드에서 예외를 잡기 위한 클래스 크게 UnChecked exception , Checked exception으로 나뉜다.
UnChecked exception , Checked exception 차이점
자바에선 Exception 클래스의 서브클래스 중에서 RuntimeException을 상속하지 않은 나머지 예외 클래스들은 체크 예외라고 생각해도 된다.
체크 예외와 언체크 예외의 차이점은 다음과 같다.
UnChecked exception | Checked exception |
예외처리를 강요하지 않음 | 예외처리를 반드시 해야함 |
런타임 단계에서만 확인이 가능함(실행 후 알 수 있다) | 컴파일 단계에서 확인이 가능함(실행 전에 알 수 있다) |
소스코드로 보자.
여기 계산기가 있다. 해당 계산기는 x 값 또는 y값이 1000 이상 넘어가면 계산을 못한다고 가정해보자.
ThousandOverException 은 Exception의 서브클래스 임으로 Checked exception 가 된다.
다음과 같이 main 메서드에서 사용하려고 하면 예외처리를 강요한다.
하지만 개발자들이 이 이상한 계산기는 1000 이상의 값은 계산 못한다고 암묵적으로 알고 있을 때는
예외처리를 강요하는 것이 효율적일까?
무언가의 규약을 알고 있다면 강요하지 않는 편이 소스코드를 좀 더 깔끔하게 작성할 수 있을 것이다.
따라서 그런 경우 UnChecked exception을 이용하는 것이 좋을 것이다.
UnChecked exception 도 원한다면 예외처리를 할 수 있다.
예외처리 방법
예외 처리 방법으로는
1. 예외 복구
2. 예외처리 회피
3. 예외 전환
이렇게 크게 3가지가 있다. 하나씩 알아보자.
예외 복구
-> 예외 상황을 체크하여 해당 문제를 해결해서 정상 상태로 돌려놓는 방법이다.
예제를 보자.
public class Solution {
public static void main(String[] args) {
List<Objec> objectNumberList =new ArrayList<>();
for (int i = 0; i < 10; i++) {
objectNumberList.add(i);
objectNumberList.add(String.valueOf(i));
}
}
}
현재 List(objectNumberList) 안에 String, int 형이 같이 공존하고 있다.
이러한 경우 해당 List 안에 있는 값을 int 형으로 변경하여 List 안에 있는 값들을 모두 더하고 싶다고 할 때..
public static void main(String[] args) {
// data setting 생략
int result = 0;
for (Object o : objectNumberList) {
int o1 = (int) o;
result+=o1;
}
}
다음과 같은 코드를 작성할 것이다. (instanceof 를이용하여 분류할 수 도 있지만 예제 임으로 이해해주세요)
하지만 해당 코드는 다음과 같은 오류가 발생한다.
당연한 오류이다.
String 형을 int 형으로 형 변환을 하지 못하여 발생하는 오류 임으로 해당 오류를 복구하여
정상적인 프로그램으로 변경해보자.
public static void main(String[] args) {
// data setting 생략
int result = 0;
for (Object o : objectNumberList) {
try {
int i = (int) o;
result+=i;
}catch (ClassCastException e){
String s = (String)o;
int i = Integer.parseInt(s);
result+=i;
}
}
}
(for문안에 try-catch 문을 작성하는 것은 매우 안 좋음으로 실제 프로그래밍을 할 때는 쓰지 않는 것을 권장합니다)
예외처리 회피
-> 예외처리를 담당하지 않고 자신을 호출한 쪽으로 던져버리는 경우이다.
아까 계산기의 코드를 보자.
public class Calculate {
static int sum(int x, int y) throws ThousandOverException {
if(x > 1000 || y>1000) throw new ThousandOverException();
return x+y;
}
}
예외가 발생하면 throws 키워드를 통해 해당 method를 호출한 쪽으로 던지고 있다.
매우 무책임한 코드 임으로 항상 사용할 때 최선의 방법일 때만 사용하도록 하자.
예외 전환
-> 적절한 예외로 전환해서 넘기는 방법
예를 들어보자.
체크 예외는 반드시 예외처리를 강요받는다.
이 뜻은 체크 예외를 던지는 Method를 사용하는 계층에서 일일이 구현해줘야 하는 번거로운 일이 발생한다.
하지만 체크 예외를 던지는 Method 안에서 언체크 예외를 던진다면?
다른 계층에서는 일일이 구현해주지 않아도 간편하게 사용할 수 있다.
public void add(User user) throws DuplicateUserIdException, SQLException {
try {
// ...생략
} catch(SQLException e) {
if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
throw DuplicateUserIdException();
}
else throw e;
}
}
커스텀한 예외 만드는 방법
해당 예외는 앞서 UnChecked exception , Checked exception 차이점 부분에서 자세히 무슨 역할을 하는지 설명하였음으로 넘어가겠습니다.
Checked exception 예외 만들기(Exception 을 상속하여 만든다)
public class ThousandOverException extends Exception {
@Override
public String getMessage() {
return "1000을 넘길수 없습니다";
}
}
UnChecked exception 예외 만들기(RumtimeException 을 상속하여 만든다)
public class ThousandOverException extends RuntimeException {
@Override
public String getMessage() {
return "1000을 넘길수 없습니다";
}
}
자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
try{
//에러가 발생할 수 있는 코드
}catch (Exception e){
//에러시 수행
e.printStackTrace(); //오류 출력
throw e; // 오류를 발생하는 키워드
}finally{
//무조건 수행
}
throws
-> 현재 메서드에서 자신을 호출한 상위 메서드로 Exception을 발생시킴
throw
-> 에러를 발생시키고자 할 때 사용(현재 메서드, 혹은 상위 메서드로)
자바 7 부터 추가된멀티 catch , 자동 리소스 닫기(try-catch-resources)
1. 멀티 catch
catch 블록에서 여러 개의 예외를 처리할 수 있도록 멀티 catch 기능이 추가 되었다.
동일하게 처리 하고 싶은 예외를 | 로 연결하면 된다.
try{
....
}catch(ArrayIndexOutOfBoundsException | NumberFormatException e){
....
}
2. 자동 리소스 닫기(try-catch-resources)
finally에서 항상 처리해줘야했던 리소스 객체(입출력 스트림, 소켓 등) 을 자동으로 정리 해준다
주의)해당 리소스 객체가 java.lang.AutoCloseable 인터페이스를 구현하고 있어야 한다
Scanner 클래스를 한번보자.
보면 Closeable 을 구현 하고 있음으로 명시적으로 호출 하지 않아도 자동으로 리소스를 정리 해준다.
Closeable 인터페이스는 다음과같이 AutoCloseable 을 상속받고있다.
'Java > live-study' 카테고리의 다른 글
[Java] 백기선 라이브 스터디 11주차 과제: Enum (0) | 2021.01.28 |
---|---|
[Java]백기선 라이브 스터디 10주차 과제: 멀티쓰레드 프로그래밍 (0) | 2021.01.20 |
[JAVA] 백기선 라이브스터디 8주차 과제: 인터페이스 (0) | 2021.01.06 |
(JAVA)백기선 라이브 스터디 7주차 : 패키지 (0) | 2021.01.01 |
[JAVA] 백기선 라이브 스터디 6주차 과제: 상속 (0) | 2020.12.26 |