CodeOnWeb
Hanyang ERICA
Log in

예외 처리

예외적인 경우들을 처리하는 코드를 프로그램에 추가하는 것

Baik Jeanseong 2018/11/21, 20:01

CSE2016 프로그램 설계 방법론

학습목표

• 예외 처리 개념 이해
• 예외 구문 이해 및 사용
• 예외 처리 클래스 만들기와 사용
• 예외 전파 이해
• 예외 클래스 계층도 이해
• 문제 해결에 예외 적용

예외의 이해

  • 예외는 프로그램을 실행할 때 발생할 수 있는 비정상적이거나 잘못된 싱황을 정의하는 객체이다.
  • 예외 처리를 통하여 예상치 못한 실행 시간 중 발생하는 문제를 적절하게 해결할 수 있다.
  • 예외는 프로그램의 정상적 실행 과정에서 발생할 수 있는 예외적인 실행 오류 조건을 나타낸다.
  • 예외를 탐지하고 처리하는 코드: 예외를 다룬다, 프로그램을 견고하게 할 수 있다.

전통적인 예외 처리

  • 프로그래머들이 에외(실행 오류) 문제를 해결한 방법은 예외 처리를 전혀 하지 않는 것이다. 대신 그들은 일반적으로 다음과 같은 두 가지의 접근법 중 하나를 사용하였다.

1. 예외를 탐지하려고 시도조차 하지 않는다.

  • 프로그램이 계획한 대로 실행될 거라고 가정하고 프로그램을 작성하는 것이다.
  • 오류를 발생시키고 난 후 나타나는 오류 메시지는 예외가 발생한 이유를 찾는 데 도움을 준다.

프로그램이 오류를 발생하도록 0으로 나누는 시도를 해본다.
한번 금액을 "10000" 그리고 책의 가격을 "0"이라고 입력해본다.

실행결과 다음과 같은 예외가 발생할 것이다.

실행결과

금액을 입력하세요: 10000
책의 가격을 입력하세요: 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ComputeNumberBooks.main(ComputeNumberBooks.java:22)

그 다음 전통적인 방법인,

2. 예외를 탐지하자마자 프로그램을 종료한다.

이를 보완하기 위해 '예외처리'를 하는데,
다음 프로그램에서는 '책의 가격은 0보다 커야 한다.'라는 오류 메시지를 출력하고 종료하도록 한다.

그러나 위와 같은 방법은 실행 오류를 단순히 무시하는 것에 지나지 않는다.
프로그램 실행 시 예상하지 못하거나 비정상적인 상황에서도 예외를 처리하는 메커니즘인 '예외 구문'을 사용한다.

예외 구문

자바의 예외 처라 방법은 먼저 비정상적이거나 예외적인 어떤 상횡이 발생하지 않을 것이라고 가정하고 프로그램을 작성 하는 것이다. 다음으로 예외적인 경우들을 처라하는 코드를 프로그램에 추가히는 것이다. 따라서 우리는 자바 프로그램이나 메소드를 정상적인 경우를 위한 코드와 예외적인 경우를 위한 코드로 분리할 수 있다.

자바에서 예외 처리는 try-catch 문에 의해 제공된다. try-catch 문은 try 블록(block)과 catch 블록으로 이루어진다 try 블록은 예외를 발생시킬 수 있는 문들을 포함하고catch 블록은 발생한 특정 유형의 예외 를 처리하는 문들을 포함한다. try-catch 문의 기본 아이디어는 정상적인 상황은 try 블록에 의해 처리하고 예외적인 상황은 catch 블록에 의해 처리하자는 것이다. try-catch 문의 구문은 다음과 같다.

  • try 블록은 연관된 여러 개의 catch 블록을 가질 수 있다. 예외는 try 블록 내의 문에서 발생할 수 있다.

  • throw 문이 예외를 발생시킨다. throw 문의 구문은 다음과 같다.

throw 문이 실행되면 명시된 예외클래스의 객제가 생성되고 해당 예외가 발생한다. 예외가 발생하면 try 블록 내의 코드는 더 이상 실행되지 않고 해당 예외 유형에 대응하는 catch 블록 내의 코드가 실행된다. catch 블록은 매개변수를 가지는 메소드 정의처럼 보인다. catch 블록은 메소드 정의가 아니지만 어떤 점에서 메소드와 같이 작동된다. catch 블록은 대응하는 try 블록 내에서 throw 문이 실행될 때 실행되는 코드이다. throw 문은 메소드 호출과 비슷하다. 그러나 메소드를 호출하는 대신에 catch 블록을 호출하고 catch 블록 내의 코드가 실행되게 한다.

catch 블록의 첫 줄을 살펴보자. 식별자 e는 매개변수처럼 보이고 매개변수와 같이 작통한다. 이 식별자는 우리에게 처리되는 예외에 대한 이름을 제공한다. 이 이름을 통하여 발생한 예외를 처리하는 코드를 catch 블록 내에 쓸 수 있다. catch 블록의 매개변수 앞에 나오는 클래스 이름은 catch 블록 내 에서 처리할 수 있는 예외 유형을 명시한다. try-catch 문을 사용하는 간단한 프로그램이 다음에 보여진다. 책의 가격이 0인지를 확인하는 if-else 문을 다음의 if 문으로 변경한다.

이 문은 입력된 책의 가격이 0이라면 Exception 객체를 생성하고 예외를 발생하게 한다. “예외 발생: 책의 가격이 0 이다!"라는 문자열은 Exception 클래스의 생성자 메소드 호출에 대한 실제 매개 변수이다. 이 문자열은 발생한 예외를 기술한다. 생성된 Exception 객체는 이 문자열을 한 객제 변수에 저장한다. Exception 객체가 예외를 발생시키면 에외 유형이 Exception이므로 다음으로 catch 블록을 수행한다. 이 때 catch 블록의 매개변수 e가 그 Exception 객제를 가라키게 된다.

모든 Exception 객체는 getMessage라는 메소드를 가진다. 이 메소드는 Exception 객체가 생성될 때 주어진 문자열을 반환한다. 그러므로 메시지 호출 e.getMessage()는 “예외발생: 책의 가격이 0 이다!"라는 문자열을 반환한다. 따라서 다음 프로그램의 catch 블록이 실행된 후의 출력 결과는 다음과 같다.

실행결과

금액을 입력하세요: 10000
책의 가격을 입력하세요: 0
예외 발생: 책의 가격이 0이다!
예외 처리: 책의 가격은 0보다 커야 한다.

예외가 발생하면 try 블록 내의 남은 문들은 실행되지 않는다. 다음 프로그램을 실행할 때 입력된 책의 가격이 0보다 크다변 예외가 발생하지 않는다. 이 경우 throw 문도 실행되지 않고 catch 블록도 실행되지 않는다.

try 블록은 연관된 여러 개의 catch 블록을 가질 수 있다. 다음은 두 개의 catch 절을 가진 try-catch 문의 구조를 보여준다.

try-catch 문이 어떻게 실행되는지를 알아보자 try 블록 내의 문들은 순서 대로 실행 된다. 그 문들 중의 하나가 에외 를 발생시키띤 제어 가 발생한 예외에 대응하는 catch 블록으로 넘겨지고 그 catch 블록 내의 문들이 실행된다. 다음으로 try-catch 문을 따르는 문을 실행 한다. 이 경우에 try 문 내의 예외가 발생한 문 다음에 있는 나머 지 문들은 실행되지 않는다 try 블록 내의 어떤 문도 예외 를 발생시키지 않는다면 catch 블록(들)은 무시되고 프로그램 실행은 try-catch 문을 따르는 문에서 계속된다.

다음 그림은 try-catch문의 두 가지 가능한 실행 사례를 보여준다. 왼쪽의 사례는 예외가 일어나는 경우이고 오른쪽의 사례는 예외가 일어나지 않는 경우이다.

file

try-catch 문은 선택적으로 finally 블록을 사용할 수 있다. try-catch 문에서 finally 블록은 예외의 발생 에 관계없이 항상 실행되는 블록이다. finally 블록은 파일과 같은 자원들을 관리하거나 알고리즘의 특정 부분들이 실행되는 것을 보장하기 위해 사용된다. 다음은 finally 블록을 포함한 try-catch 문을 보여준다.

예외 클래스 만들기

우리는 새로운 예외 클래스를 만들 수 있다. 그러나 새 예외 클래스는 이미 정의된 예외 클래스의 하위 클래스여 야 한다. 즉 한 예외 클래스는 자바 클래스 라이브러리 내의 이미 정의된 예외 클래스나 우리가 이미 정의한 어떤 예외 클래 스의 하위 클래스일 수 있다.
한 예외 클래스를 정의할 때 생성자 메소드들이 가장 중요하고 유일한 메소드들이다. 물론 상위 클래스의 메소드들을 상속받을 수 있다. 다음 프로그램에 보여질 간단한 예외 클래스를 살펴보자.

이 예외 클래스는 어떤 수를 0으로 나누려고 시도할 때 발생하는 예외를 모델한다. 이 에외 클래스의 이름은 DivideByZeroException이다. 이 클래스는 Exception 클래스의 하위 클래스이다. 이 예외 클래스의 유일한 메 소드들은 기본 생성자 매소드와 한 개 의 매 개변수를 갖는 생성자 메소드이다. 현재로서는 이 메소드들이 예외 클래스 내에 필요한 전부이다. 기본 생성자 메소드 내에 있는 유일한 자바 문은 다음과 같다.

위 문은 상위 클래스인 Exception 클래스의 생성자 메소드를 호출한다. 이때 “0으로 나누려고 시도 1"라는 문자열을 넘겨 준다. 이 문자열이 해당 DivideByZeroException 객체의 한 객체 변수에 저장된다. 우리는 후에 getMessage메소드를 호출하여 이 문자열을 얻을 수 있다. getMessage 메소드는 Exception 클래스의 메 소드이고 DivideByZeroException 클래스에 상속된다. 다음 프로그램은 DivideByZeroException 클래스를 이용하는 예제 프로그램이다.

이 프로그램은 이전 Exception을 새로 정의된 DivideByZeroException 클래스로 대체한 프로그램이다.
따라서 DivideByZeroException 예외는 다음 throw 문에 의해 발생된다.

발생된 예외는 예외 유형이 DivideByZeroException 클래스이기 때문에 catch 블록에 의해 처리된다.

실행결과

금액을 입력하세요: 10000
책의 가격을 입력하세요: 0
예외 발생: 책의 가격이 0이다!
예외 처리: 책의 가격은 0보다 커야 한다.

예외 발생과 전파

어떤 경우에는 예외 처리를 미루는 것이 더 적절할 수 있다. 예를 들면 한 메소드 내에서 예외가 발생할 때 그 메소드에서 예외를 처리하지 않을 수 있다. 왜냐하면 그 메소드를 사용하는 어떤 프로그램은 예외가 발생하면 프로그램이 종료되어야 하고 다른 프로그램은다른 일을 해야 하기 때문이다. 그 결과로 그 메소드 내에서 발생한 예외를 어떻게 처리해야 할 지 알 수 없는 경우가 있다. 이런 경우에는 메소드 정의에서 예외를 처리하지 않도록 명시하는 것이 적절하다. 대 신에 예외를 발생시킨 메소드를 호출한 메소드에서 메소드 호출문을 try 블록 안에 포함시키고 대응하는 catch 블록에서 예외 처리를 하게 한다. 이를 예외 전파라고 부른다. 예외 전파는 예외가 인식되어 처리될 때까지 계속된다. 만약 프로그램 제어가 main 메소드까지 넘어갔는데도 예외가 인식되어 처리되지 않는다면 프로그램은 종료되고 예외 관련 오류 메시지를 출력한다. 한 메소드는 직접 예외를 발생시키거나 예외 를 발생시커는 메소드를 호출함으로써 간접적으로 예외를 발생시킬 수 있다. 이 메 소드는 예외 발생자(exception thrower)라고 부른다. 모든 예외 발생자는 예외 처리자(exception catcher) 혹은 예외 전파자(exceptionpropagator) 여야 한다. 예외 처리자는 발생한 예외에 대응하는 catch 블록을 포함하는 메소드이다. 반면에 에외 전파자는 대응하는 catch 블록을 포함하지 않는 메소드이다. 예외가 한 메소드에서 일어나면 그에 대응해서 우리는 다음 두 가지 중의 하나를 할 수 있다.

  1. 예외를 바로 그 자랴에서 인석하여 처리한다.
  2. 메소드 머리 부에 호출한 메 소드가 예외를 처리해야 한다고 선언한다.

예외 를 처리하는 방법을 알기에 충분한 정보를 가지고 있다면 첫 번째 방법 을 사용한다 그렇지 않다면 두 번째 방법을 사용한다. 예외 처리의 두 번째 방법에서 메소드 머리부에 호출한 메 소드가 예외 를 처리 해야 한다고 선언하기 위해 throws 절을 메소드 마랴부에 추가한다. 예를 들면 메 소드 aMethod가 DivideByZeroException이라는 예외를 발생시키고 처리하지 않는다면 메소드 머리부를 다음과 같이 작성한다.

throws 절은 aMethod의 실행 중 DivideByZeroException이라는 예외가 발생할 수 있다는 것을 의미한다. 또한 발생한 예외 는 aMethod라는 메소드에서 처리되지 않고 aMethod를 호출한 메 소드에서 처랴될 수 있다는 것을 뜻한다. throws 절은 한 개 이상의 예외 유형 을 포함할 수 있다. 그러한 경우에 우리는 다음과 같이 예외 유형 들을 콤마(,)로구분한다.

다음 프로그램을 살펴보자. 책들의 최대 권수를 계산하는 별도의 메소드 computeNumberBooks를 만들고 이 메소드에서 입력된 책의 가격이 0 이면 DivideByZeroException 예외를 발생시킨다. 하지만 예외 처리는 하지 않는다. 이는 메소드 머리부의 throws 절에 명시되어 있다. 발생한 예외는 computeNumberBooks 메소드를 호출한 main 메소드에서 처리된다. main 메소드에서 computeNumberBooks 메소드를 호출하는 문이 try 블록 안에 포함되어 있고 대응하는 catch 블록에서 DivideByZeroException 예외를 처리함에 유의하라.

실행결과

금액을 입력하세요: 10000
책의 가격을 입력하세요: 0
예외 발생: 책의 가격이 0이다!
예외 처리: 책의 가격은 0보다 커야 한다.

다음 그림에 보여진 메소드 호출 순서를 고려해보자. 메소드 A는 메소드 B를 호출하고 메소드 B는 메소드 C를 호출한다. 그림에는 메소드 호출을 추적하기 위한 스택 (stack) 이 있다는 것을 유념하라. 메소드가 호출될 때마다 메소드의 이름이 메소드 호출 정보를 포함하는 스택의 맨 위에 놓여진다. 메소드 C가 실행될 때 우리는 스택에 A, B, C를 가진다.

file

예외가 발생할 때 시스템은 스택의 맨 위 부터 아래로 첫 번째 대응하는 예외 처리자를 찾기 위해 검사한다. 메소드 C가 예외를 발생시카나 그 메소드 내 에는 대응하는 catch 블록이 존재하지 않으므로 메 소드 C는 예외 전파자이다. 다음으로 시스템은 메 소드 B를 검사한다. 이 메소드 역시 대응하는 catch 블록을 포함하고 있지 않으므로 예외 전파자이다. 마지막으로 시스템은 메소드 A에서 대응하는 catch 블록을 찾는다. 그러므로 메소드 A가 메 소드 C에 의해 발생한 예외 에 대한 처리자이다. 한 메소드가 예외 전파자라면 우리는 그 메소드의 머리부에 전파하는 예외의 유형을 선언해야 한다. 우리는 이 선언을 하기 위해 throws 라는 예약어를 사용한다. 따라서 다음 그림에 있는 메소드 B와 C의 머리부는 다음과 같아야 한다.

메소드 머리부에 요구되는 throws 절이 없다면 그 프로그램은 컴파일되지 않을 것이다.

큐의 예외 처리

실제 프로그램에서 자주 사용되는 큐(queue) 데이터 구조를 모델한 클래스를 통해 발생 가능한 예외를 정의하는 방법을 학습하고 예외 발생시 예외 처리를 구현하는 방법을 배워보자. 큐는 맨 처음에 들어간 항목이 가장 먼저 나오는 FIFO(Fisrt In First Out) 자료구조이다. 실생활에서 큐의 예를 든디면 공중전화박스 앞에 기다리고 있는 사람들의 줄을 생각할 수 있다. 즉 공중전화를 이용하려는 사람 중 먼저 줄을 선 사람은 먼저 줄에 서 나와 공중전화를 이용할 수 있다. 큐의 가장 기본적인 연산은 큐에 넣기 (enqueue)와 큐에서 꺼내기(dequeue)이다.

예외처리모델

클래스 큐(Queue)를 정의할 때 반드시 고려할 사항들이 있다. 예를 들면 큐의 용량이 채워져 있을 때 큐에 넣기 연산을 수행하는 경우를 생각해 보자. 이 경우 큐가 꽉 차 있어 새 항목을 넣을 수가 없으므로 예외가 발생한다. 이 문제 에 대해 다음과 같이 여러 가지의 해결 방안이 있을 수 있다.

• 큐의 용량을 늘린다.
• 큐에 넣기 연산을 실행하지 않는다.
• 새 항목을 큐에 넣기 위하여 큐에서 한 항목을 강제로 꺼낸다.

반대로 큐가 비어 있을 때 큐에서 꺼 내 기 연산을 수행하는 경우도 생각할 수 있다. 이 경우 큐가 비어 있다면 꺼낼 수 없으므로 예외가 발생한다. 따라서 이 경우에도 예외 처리를 해야한다.

예외 생성

자바에서는 여러분야 이용할 예외를 직접 만들 수 있다. 이 예외의 작성은 일반 클래스의 작성과 통일한 방법으로 이루어진다. 모든 예외와 관련된 새 클래스는 Exception 클래스의 하위 클래스가 될 수 있다. 다음은 QueueEmpty Exception 클래스를 정의하는 간단한 코드이다. 예외 QueueEm pty Exception은 큐가 비어 있는 경우 큐에서 꺼내기 연산을 하는 경우에 발생하는 예외 를 나타내는 클래스이다.

위에서 정의한 에외 클래스 QueueEmptyException을 이용하는 아래 코드를 살펴보자. 클래스 Queue 내의 메소드 dequeueO 에서 큐가 비어 있으면 QueueEmpty Exception이 발생한다. 그러나 dequeue 메소드에서 그 여l 외를 처라하지 않는다. 따라서 메소드 dequeue() 의 머리부에 이 메소드는 QueueEmptyException 예외를 발생시킬 수 있다는 사실을 기술하고 있다. 그러므로 메소드 dequeue()를 호출하는 부분에서는 예외 QueueEmptyException이 발생 할 수 있다는 가정하에서 예외 처리 모듈을 구현하여야 한다.

위에서 정의한 Queue 클래스를 이용하는 예를 살펴보자. 고객과 출납원(cashier)를 모델 하는 다음 코드를 살펴보자. 클래스 Cashier의 메소드 getNextCustomer에서는 클래스 Queue의 메소드 dequeue()를 호출한다. 그러나 메소드 getNextCustomer에서는 메소드 dequeue에서 발생할 수 있는 QueueEmptyException 예외에 대한 처리 모듈이 없기 때문에 컴 파일 에러가 발생할 수 있다.

메소드 getN extC u stomer에서 발생하는 컴파일 에러는 다음 두 가지 방법으로 제거할 수 있다.

  1. QueueEmptyException 예외의 처리 모률을 try-catch 문을 이용하여 구헌한다.

  1. 메소드 getNextCustomer에서 QueueEmptyException 예외의 처리를 자신을 호출한 다른 메소드로 전파시킨다. 이를 명확하게 기술하기 위해 메소드 getNextCustomer의 머리부를 다음과 같이 수정한다. 그러먼 getNextCustomer 메소드를 호출한 메소드로 예외 처리의 책임이 전가되게 된다.

예외의 종류

예외에는 두 가지 유형이 있다. 첫 번째 유형은 점검 받는 예외 (checked exception) 이고 두 번째 유형은 점검 받지 않는 예 외 (unchecked exception) 이다. 점검 받는 예외는발생하면 catch 블록에서 처리 되 거나 throws 절을 통해 처리를 호출한 메소드로 넘겨야 한다. 점검 받는 예외는 자주 프로그램을 종료하게 하는 심각한 문제들을 나타낸다. 자바 클래스 라이브러리에 있는 점검 받는 예외들의 예 는 ClassNotFoundException, IOException과 NoSuchMethodException 등이다. 점검 받지 않는 예외는 컴파일할 때 점검 받지 않고 실행 시에만 탐지되기 때 문에 실행시간 예외라고도 부른다. 이 예 외는 보통 프로그램 내에 틀린 것이 있고 오류를 고쳐야 한다는 것을 나타낸다. 한 숫자를 0으로 나누려고 시도하는 것이 실행시간 예외의 한 예이다. 실행시간 예 외는 예외 처리를 반드시 해야 할 의무는 없다. 예를 들면 다음 코드에서 발생하는 예 외 는 실행시간 예 외 이 므로 try-catch 문을 사용하지 않고 메 소드 머리부에 예외를 전파하는 선언이 없어도 컴파일 시 오류가 발생하지 않는다.

처리되지 않는 실행 시간 예외는 발생하면 프로그램을 종료하게 만든다. 한 메소드가 점검받는 예 외들의 전파자라면 그 메소드는 throws 절을 가져야 한다. 한 메소드가 실행시간 예외들 혹은 오류들의 전파자라면 throws 절은 선택사항이다. 우리가 점검 받는 예외들을 발생시킬 수 있는 메소드를 호출할 때 우리는 try-catch 문을 사용해야 하고 메소드 호출문을 try 블록 안에 포함시켜야 한다. 그렇지 않으면 우리는 적절한 throws 절을 포함시거기 위해서 메소드 머리부를 수정해야 한다. 우리가 실행시간 예외들 혹은 오류들을 발생시킬 수 있는 메소드를 호출할 때에는 그러한 요구사항이 없다. 우리는 단지 한 메소드 내에서 다른 메소드를 호출한다. 자바 에서는 점검 받는 에외와 점검 받지 않는 예외를 모두 클래 스로 정의하여 다루고 있다. 필요하디띤 새로운 예외 를 정의하여 이용할 수 있다. 자바에서 한 예외는 Throwable 클래스 혹은 그 클래스의 하위 클래스들의 객체로서 나타내진다. Throwable 클래스는 Error 와 Exception 이라는 두 개의 하위 클래스들을 가진다. Error 클래스는 오류를 나타낸다. 오류는 예외와 비슷하지만 예외가 아니다. Error 클래스는 주로 하드웨어 관련 오류를 나타내는 클래스이다. 예를 들면 메모라 파괴 메모리 부족과 히드디스크 포뱃이 망가진 경우이다. Error 클래스와 그 클래스의 하위 클래 스들은 보통 프로그램에 의해 처리 되어서는 안 되는 심각한 문제들을 나타낸다. 반면에 Exception 클래스와 그 클래스의 하위 클래 스들은 프로그램에서 처리되어야 하는 오류들을 나타낸다.

다음 그림은 자바가 제공하는 에외 관련 클래스들의 계층 구조를 보여준다. 점검 받지 않는 예외는 프로그램 실행 시 발생하는 예외 를 나타낸다. 이 예외의 예는 잘못된 유형 변환(casting)의 경우에 발생하는 ClassCastException, 배열의 크기를 초과하여 접근하는 경우에 발생하는 ArraylndexOutOfBoundsException, 0으로 나누는 등의 산술적인 예외의 경우는 ArithmeticException, 배열의 크기를 지정할 때 음수를 사용할 경우에 발생하는 NegativeArraySizeException, null 값을 갖는 객체 변수의 메소드나 변수에 접근할 때 발생하는 N ullPoin ter Exception 등이 있다. 그리고 점검 받는 예외는 발생하면 처리되어야 하는 예외이다. 이 예외의 예는 존재하지 않는 파일을 열고자 할 때 발생하는 FileNotFoundException 등이 있다.

file

try-catch 문에서 하나의 try 블록에 대응되는 여러 개의 catch 블록을 사용할 수 있다. 즉 try- catch 문에 여러 개의 catch 블록이 있을 수 있다. 이 경우에 try 블록에서 예외가 발생하면 catch 블록들을 순서대로 확인한다. 따라서 더 특별한 예외 클래스들을 더 일반적인 예외 클래스들보다 먼저 확인히는 것이 중요하다. 따라서 예외 처리에서 예외에 관련된 클래스 간의 계층 구조를 고려하여 catch 블록을 작성하여야 한다. 간단한 예를 들어 보자. 다음 그림에 보여진 예외 QueueFullException, FileNotFoundException, IOException 사이의 계층 구조를 고려하자 이러한 계층 구조를 갖는 경우에 예외 처리를 위해 아래 코드와 같이 catch 블록을 기술한다면 컴파일 시간에 오류가 발생한다. 왜냐하면 FileN otFoundException 예외는 IOException 예외이기 때문에 try 블록에서 FileNotFoundException 예외가 발생하면 첫 번째 catch 블록이 수행된다. 따라서 두번째 catch 블록은 결코 실행되지 않는다.

file

위 코드는 아래 와 같이 수정해야 컴 파일 오류가 발생하지 않는다. 따라서 catch 블록들의 순서가 중요하다.

예제 프로그램 작성

우리는 작은 편의점에서 고객들이 산 물건 값을 지불하기 위해 줄을 서는 상황에서 출납원이 줄 순서대로 고객들을 처랴하는 과정을 시율례이션하려고 한다. 고객은 이름이 었다. 출납원은 줄 순서대로 한 명씩 고객들을 처리한다. 줄에는 최대 10명의 고객들이 있을 수있다. 고객 이 줄에 서려고 하면 줄의 끝에 서야 하고 출납원에게 물건 값을 지불하기 위해서는 줄의 맨 앞에 있고 출납원이 처리하는 고객이 없어야 한다. 이 문제를 해결하기 위한 프로그램에서 필요한 클래스들은 다음 표에 보여진다.

file

다음으로 각 클래스를 설계하자. 고객을 모멀하는 Customer 클래스는 이름을 나타내는 변수와 생성자 메소드와 이름을 알려 주는 메소드를 가진다. 고객들의 줄을 모델하는 Queue 클래스는 변수로 줄을 나타내는 크기가 10 인 벡 터 (Vector)와 줄에 서는 것을 나타내는 enqueue 메소드와 줄에서 나오는 것을 나타내는 dequeue 매소드와 줄이 비어 있는지를 일려 주는 isEmpty 메 소드가 있다. dequeue 메소드에서 줄이 비어 있는 경우에는 줄에서 나올 수 없으므로 QueueEmptyException 예 외가 발생할 수 있다. Queue 클래스에서 Vector 클래스의 다음과 같은 유용한 메 소드들을 이용한다.

• firstElement(): 맨 앞에 있는 element를 반환한다.
• addElement(Object element) 메소드: 맨 끝에 element를 추가한다.
• removeElement (Object element) 메소드: element를 제거한다.

출납원을 나타내 는 Cashier 클래스는 고객들의 줄을 나타내는 변수를 가지고 고객들의 줄에 고객을 추가하는 메 소드와 고객들의 줄의 맨 앞에 있는 다음 고객의 계산을 처리하는 메소드를 가진다. Driver 클래스는 세 명 의 고객이 줄을 서게 하고 순서대로 4명의 고객들의 물건 값의 계산을 처리하는 과정을 시율례 이 션한다. 줄에 3명의 고객이 있는 데 4명의 고객을 처리하려고 하다 보니 네 번째 고객을 처리 하려고 시 도할 때 QueueEmpty Exception이 발생한다.

다음 프로그램은 고객 서비스 프로그램을 보여준다.

출력결과

고객 고객1님이 계산하셨습니다.
고객 고객1님이 계산하셨습니다.
고객 고객1님이 계산하셨습니다.
기다리는 고객이 없어서 예외(QueueEmptyException)이 발생한다.

위 결과에 대해 설명 해 보자. 고객 1. 2. 3 이 차례로 줄에 저장된다. 그 다읍 3 번의 dequeue() 메소드에 의해 차례로 세 명 의 고객이 줄에서 빠져 나간다. 4 번째 고객을 dequeue할 수 없기 때문에 바로 catch 블록을 수행하며 e.toString() 메소드에서 예외의 한 종류인 QueueEm pty Exception을 출력하게 된다. 그리고 Cashier 클래스의 etNextCustomer 메소드에 서 메소드 호출 customerQueue.dequeue() 의 반환 값은 형이 Object이기 때문에 Customer 로의 형 변환이 필요하다. 왜냐하면 cust의 형이
Customer() 이기 때문이다.

요 약

• 예외는 프로그램을 실행할 때 발생할 수 있는 비정상적이거나 잘못된 상황을 정의하는 객체이다.
• 예외가 복구 가능한 오류라면 에러는 복구가 불가능한 오류를 말한다. 자바에서는 이러한 예외와 에러를 모두 클래스로 정의하여 다룬다.
• 예외 처리는 try-catch 문에 의해 제공된다 try 블록은 예외를 발생시킬 수 있는 문들을 포함하고 catch 블록은 발생한 특정 유형의 예외를 처리하는 문들을 포함한다.
• throw 문이 예외를 발생시킨다.
• try- catch 문에서 하나의 try 문에 여러 개의 catch 절이 있을 수 있다.
• try-catch 문에서 finally 절은 예외의 발생에 관계없이 항상 실행되는 블록이다.
• 새로운 예외는 Exception 클래스 혹은 그 클래스의 자손 클래스를 확장하여 정의된다.
• 예외가 일어난 곳에서 탐지되지 않아 처리되지 않는다변 에외가 발생한 메소드를 호출한 메소드로 예외 처리가 전가된다.
• 한 메소드에서 처리되지 않는 예외들에 대해서 그 메소드의 머리부에 throws 절이 포함되어야 한다.
• 예외에는 점검 받는 예외와 점검 받지 않는 예외가 있다.
• 점검 받는 예외는 발생하면 catch 블록에서 처리되거나 throws 절을 통해 처리를 호출한 메소드로 넘겨야 한다.
• 점검 받지 않는 예외는 실행시간 예외라고 불리고 예외 처리를 반드시 해야 할 의무는 없다.
• 프로그래머는 예외들이 어떻게 어디서 처리되어야 하는지를 주의갚게 고려해야 한다.

3836 reads

Author

No discussion

Please log in to leave a comment

16.5.11618.20190612.allo
Report · Terms of Service · Privacy Policy
Lablup Inc. · Teheran-ro 145, Gangnam-gu, Seoul, Republic of Korea · 대표: 신정규 · 사업자번호: 864-88-00080 · +82 70-8200-2587

Decline Confirm

Close
Favorite Bookmark Discussion

Please copy the following address