본문 바로가기
개발/JAVA

[JAVA] 예외처리 Exception

by 경주초이 2020. 6. 24.

예외는 언제 발생하는가?


에러를 처리하는 방법을 알기 전에 어떤 상황에서 에러가 나는지 한번 보자. 오타를 쳤을 때 나는 구문 에러 같은 것이 아닌 실제 프로그램에서 잘 발생하는 에러를 보기로 하자. 먼저 없는 파일을 열려고 시도해 보자.

BufferedReader br = new BufferedReader(new FileReader("나없는파일"));
br.readLine();
br.close();

위코드를 실행하면 다음과 같은 오류가 발생한다.

Exception in thread "main" java.io.FileNotFoundException: 나없는파일 (지정된 파일을 찾을 수 없습니다)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(Unknown Source)
    at java.io.FileInputStream.<init>(Unknown Source)
    at java.io.FileReader.<init>(Unknown Source)
    ...

위의 예에서 보듯이 없는 파일을 열려고 시도하면 FileNotFoundException라는 이름의 예외가 발생하게 된다.

이번에는 또 하나 자주 발생하는 에러로 0으로 어떤 다른 숫자를 나누는 경우를 생각해 보자.

int c = 4 / 0;
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Test.main(Test.java:14)

 

마지막으로 한가지 에러만 더 들어 보자. 다음의 에러는 정말 빈번하게 일어난다.

int[] a = {1, 2, 3};
System.out.println(a[3]);
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
    at Test.main(Test.java:17)
    

a는 {1, 2, 3}이란 배열인데 a[3]은 a 배열에서 구할 수 없는 값이기 때문에 ArrayIndexOutOfBoundsException가 나게 된다. 자바는 이런 예외가 발생하면 프로그램을 중단하고 에러메시지를 보여준다.

 

예외 처리하기


자, 이제 유연한 프로그래밍을 위한 예외처리의 기법에 대해서 살펴보자. 다음은 예외처리를 위한 try, catch문의 기본 구조이다.

try {
    ...
} catch(예외1) {
    ...
} catch(예외2) {
    ...
...
}
int c;
try {
    c = 4 / 0;
}catch(ArithmeticException e) {
    c = -1;
}

finally

public class Test {
    public void shouldBeRun() {
        System.out.println("ok thanks.");
    }

    public static void main(String[] args) {
        Test test = new Test();
        int c;
        try {
            c = 4 / 0;
        } catch (ArithmeticException e) {
            c = -1;
        } finally {
            test.shouldBeRun();
        }
    }
}

throws

public void sayNick(String nick) throws FoolException {
    if("fool".equals(nick)) {
        throw new FoolException();
    }
    System.out.println("당신의 별명은 "+nick+" 입니다.");
}


트랜잭션 (Transaction)

갑자기 "트랜잭션"이라는것이 나와서 뜬금없다고 생각할 수도 있겠지만 트랜잭션과 예외처리는 매우 밀접한 관련이 있다. 

트랜잭션은 하나의 작업 단위를 뜻한다.

쇼핑몰의 "상품발송"이라는 트랜잭션을 가정 해 보자.

"상품발송"이라는 트랜잭션에는 다음과 같은 작업들이 있을 수 있다.

  • 포장
  • 영수증발행
  • 발송

이 3가지 일들 중 하나라도 실패하면 3가지 모두 취소하고 "상품발송"전 상태로 되돌리고 싶을 것이다. (모두 취소하지 않으면 데이터의 정합성이 크게 흔들리게 된다. 이렇게 모두 취소하는 행위를 보통 전문용어로 롤백(Rollback)이라고 말한다.)

프로그램이 다음과 같이 작성되어 있다고 가정 해 보자. 

상품발송() {
    포장();
    영수증발행();
    발송();
}

포장() {
   ...
}

영수증발행() {
   ...
}

발송() {
   ...
}

쇼핑몰 운영자는 포장, 영수증발행, 발송이라는 세가지 중 1가지라도 실패하면 모두 취소하고 싶어한다. 이런경우 어떻게 예외처리를 하는 것이 좋겠는가? 

다음과 같이 포장, 영수증발행, 발송 메서드에서는 예외를 throw하고 상품발송 메서드에서 throw된 예외를 처리하여 모두 취소하는 것이 완벽한 트랜잭션 처리 방법이다.

상품발송() {
    try {
        포장();
        영수증발행();
        발송();
    }catch(예외) {
       모두취소();
    }
}

포장() throws 예외 {
   ...
}

영수증발행() throws 예외 {
   ...
}

발송() throws 예외 {
   ...
}

'개발 > JAVA' 카테고리의 다른 글

[SpringBoot] Interceptor 설정  (0) 2020.08.13
[JAVA] Thread  (0) 2020.06.25
[JAVA] 다형성  (0) 2020.06.21
[JAVA] 인터페이스  (0) 2020.06.17
[JAVA] 생성자  (0) 2020.06.15