클라이언트/ 서버/ 엔지니어 " 게임 개발자"를 향한 매일의 공부일지

반복문과 배열 그리고 예외 처리 20 - 자바의 예외 처리 본문

프로그래밍 언어/자바

반복문과 배열 그리고 예외 처리 20 - 자바의 예외 처리

huenuri 2024. 8. 14. 12:02

예외 처리는 수업에서는 한참 뒤에 다루게 되지만(클래스 수업을 마치고) 책에서는 메소드 바로 뒤에 나오는 내용이다. 이 부분이 참 고민이 되었는데 난 예외처리를 지금 학습하기로 했다. 그래야 단원 마무리 연습문제도 풀 수 있을 것 같다.

나중에 다루는 예외처리는 그때 가서 정리해보기로 하자.


 

 

 

예외(Exception)란?

자바에서 오동작이나 결과에 악영향을 미칠 수 있는 실행 중 발생한 오류를 말한다. 문법에 맞지 않게 작성된 코드는 사전에 컴파일러에 의해 컴파일 오류로 걸러낸다. 하지만 예외는 사용자의 잘못된 엽력이나 배열의 인덱스가 배열의 크기를 넘어가는 등 예기치 못한 상황에 의해 프로그램 실행 중에 발생한다.

다음은 예외가 발생하는 경우이다.

 

  • 정수를 0으로 나누는 경우
  • 배열의 크기보다 큰 인덱스로 배열의 원소를접근하는 경우
  • 존재하지 않는 파 일을 읽으려고 하는 경우
  • 정수 입력을 기다리는 코드가 실행되고 있늘 때, 사용자가 문자를 입력한 경우

실행 중에 예외가 발생하면 자바 플랫폼이 가장 먼저 알게 되어, 현재 실행 중인 응용프로그램에게 예외를 전달한다. 만약 응용프로그램이 예외에 대처하는 코드를 가지고 있지 않다면, 자바 플랫폼은 응용프로그램을 곧바로 종료시킨다.

 

 

 

 

 

예외 발생 사례


 

 

 

1. 0으로 나누기 예외 발생으로 프로그램이 강제 종료되는 경우

두 정수를 입력 받아 나눗셈을 하고 몫을 구하는 프로그램이다. 사용자가 나누는 수에 0을 입력하면 arithmeticException 예외가 발생하여 프로그램이 강제 종료된다.

 

 

 

0으로 나눌 때는 다음과 같이 예외가 발생하는 것을 볼 수 있다.


 

 

 

예외 처리, try-catch-finally 문

예외 처리란 개발자가 작성한 프로그램의 실행 중에 예외가 발생하면 이에 대응하는 것을 말한다. 자바는 예외 처리를 위해 try-catch-finally 문을 사용한다.

 

 

예외가 발생할 가능성 있는 실행문들을 try {  } 블록으로 묶고, 예외 처리 코드는 catch {  } 블록 내에 작성한다. catch() 문의 () 안에는 처리하고자 하는 예외의 타입을 선언한다. catch { } 블록은 예외마다 하나씩 작성되어야 한다.

 

 

try 블록에서 예외가 발생하면 응용프로그램은 남은 실행문을 실행하지 않고 바로 catch 블록의 예외 처리문으로 점프하여 실행한다. 물론 발생한 예외의 타입과 일치하는 catch() 블록으로 점프한다.

finally { } 블록은 생략해도 상관없으며 실제로 많은 경우 생략한다. finally 블록은 예외가 발생하든 않든 마지막에 반드시 실행된다.


 

 

 

 

 

자바의 예외 클래스

응용프로그램에서는 자바 플랫폼에서 제공하는 예외 클래스를 이용하여 예외 발생을 탐지할 수 있다. 실행 중 try 블록 내에서 예외가 발생하면, 자바 플랫폼은 catch() 문의 '처리할 예외 타입 선언'부에 객체로 만들어 전달된다. 예외 객체는 발생한 예외에 대한 정보를 제공한다.

 

 

 

다수의 예외를 처리하고자 하는 경우에는 여러 개의 catch 블록을 연속적으로 작성할 수 있으며, 발생한 예외와 타입이 일치하는 catch 블록이 실행된다.

만약 발생한 예외 타입과 일치하는 catch 블록이 없으면 프로그럼은 강제 종료된다. catch 블록 내에서 System. exit(0)을 호출하면 언제든지 프로그램을 종료할 수 있다.


 

 

 

 

2. 0으로 나눌 때 발생하는 AritmeticException 예외 처리

try-catch 블록을 이용하여 이전 예제를 수정한다. 정수를 0으로 나누는 경우에 “0으로 나눌 수 없습니다!”를 출력하고 다시 입력 받는 프로그램을 작성한다.

 

 

 

이렇게 0으로 나누려고 할 때 예외가 발생하며 그 예외 문구가 출력되는 것을 볼 수 있다. 조금 전의 예제에서는 예외 처리가 되면 프로그램이 종료되었지만, 여기서는 while 문을 반복하고 정상적으로 나누기가 실행되면 break를 통해 빠져나간다.


 

 

 

 

범위를 벗어난 배열의 접근( ArrayIndexOutOfBoundsException)

배열의 인덱스가 범위를 벗어날 때 ArrayIndexOutOfBoundsException을 처리하는 프로그램을 작성한다.

 

 

 

이렇게 배열의 길이가 4를 넘어서면 예외 문구가 출력된다. 하지만 왜 arr의 값이 0, 1, 3, 6이 되는지 이해가 되지 않았다.


값이 0, 1, 3, 6이 되는 과정

for(int i = 0; i < 5; i++) {
    arr[i+1] = i+1 + arr[i];    // i가 4인 경우 예외 발생
    System.out.println("arr[" + i + "]" + " = " + arr[i]);
}

 

  • i = 0:이 시점에서 배열의 상태는 [0, 1, 0, 0, 0]이다.
arr[1] = 1 + arr[0]; // arr[1] = 1 + 0 = 1

 

  • i = 1:이 시점에서 배열의 상태는 [0, 1, 3, 0, 0]이다.
arr[2] = 2 + arr[1]; // arr[2] = 2 + 1 = 3

 

  • i = 2:이 시점에서 배열의 상태는 [0, 1, 3, 6, 0]이다.
arr[3] = 3 + arr[2]; // arr[3] = 3 + 3 = 6

 

  • i = 3:이 시점에서 배열의 상태는 [0, 1, 3, 6, 10]이다.
     
arr[4] = 4 + arr[3]; // arr[4] = 4 + 6 = 10

 

  • i = 4:이 시점에서 arr[5]는 존재하지 않으므로 ArrayIndexOutOfBoundsException 예외가 발생한다. 예외가 발생하면서 catch 블록이 실행되고, "배열의 인덱스가 범위를 벗어났습니다."라는 메시지가 출력되는 것이다.

 

 

 

 

3. 입력 오류시 발생하는 예외(InputMismatchException)

3개의 정수를 입력 받아 합을 구하는 프로그램을 작성해보자. 사용자가 정수가 아닌 문자를 입력할 때 발생하는

InputMismatchException 예외를 처리하여 다시 입력 받는다.

 

 

 

i++을 하게 되면 인덱스가 더는 생성되지 않아서 끊겨버린다. 그렇기에 i--를 해서 인덱스가 다시 생성되도록 하는 거였다. i++은 루프의 다음 반복에서도 i가 증가하는 것을 의미하므로, i의 값이 두 번 증가한다. 예를 들어 i가 0일 때 예외가 발생하면 i가 2가 되며, 1을 건너뛰게 된다.

이는 입력 오류가 발생한 경우 다시 입력을 요구하지 않고, 인덱스가 2번 증가해 버리는 결과를 초래한다.


 

 

 

 

 

4. 정수가 아닌 문자열을 정수로 변환할 때 예외 발생(NumberFormatException)

문자열을 정수로 변환할 때 발생하는 NumberFormatException을 처리하는 프로그램을 작성해보자.

 

 

3.141592는 정수가 아니므로 예외가 발생하여 이 문구가 출력된다. 하지만 그 다음 문장을 출력되지 않는데 try 블록 내에서 예외가 발생하면 즉시 해당 블록의 실행이 중단되고 catch 블록으로 넘어가기 때문이다.

만약 다음 문자열도 실행이 되게 하려면 어떻게 해야 할까?


 

 

모두 출력되도록 코드 수정하기

 

 

이 코드는 비슷해보이지만 큰 차이가 있다.

  • 원래 코드에서는 try-catch 블록이 루프 바깥에 있다. 즉, for 루프 전체가 하나의 try-catch 블록으로 감싸져 있다. 이 경우, 예외가 발생하면 for 루프 전체가 중단되고, 그 이후의 요소들은 더 이상 실행되지 않는다.
  • 수정된 코드에서는 try-catch 블록이 루프 안쪽에 있다. 루프의 각 반복마다 try-catch 블록이 실행된다. 예외가 발생해도 해당 반복만 종료되고, 다음 반복이 계속해서 실행된다. 이를 통해 예외가 발생한 이후에도 나머지 요소들이 정상적으로 처리된다.

 

 

 

 

핵심 체크 문제 풀기

 

 

2번의 (2)번은 틀렸다. 자료형을 잘못 입력한 게 아니고 NumberFormatException으로 문자열을 정수로 변환할 때 발생하는 오류이다.


 

 

 

학습을 마치고

이렇게 해서 예외 처리 학습을 모두 마쳤다. 공부하기 전에는 예외 처리를 무척 어렵게 생각했는데 실제로 해보니 별로 그렇지 않았다. 이제 3장 단원의 연습문제만을 남겨놓고 있다. 수업은 5장까지만 진행이 되어 나머지 2/3는 혼자서 공부해야 한다.

그래도 난 자바가 무척 재미있어서 책의 끝까지 모두 학습해보고 싶다.