문서의 선택한 두 판 사이의 차이를 보여줍니다.
양쪽 이전 판 이전 판 다음 판 | 이전 판 | ||
study:java:javachobo:ch8 [2010/02/15 13:35] gauryan |
study:java:javachobo:ch8 [2010/03/08 08:51] (현재) gauryan |
||
---|---|---|---|
줄 12: | 줄 12: | ||
* 정의 : 프로그램 실행시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것 | * 정의 : 프로그램 실행시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것 | ||
* 목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것 | * 목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것 | ||
- | |||
===== 예외처리구문 : try-catch ===== | ===== 예외처리구문 : try-catch ===== | ||
- | ===== try-catch문에서의 흐름 ===== | + | * 예외를 처리하기 위해서는 |
- | ===== 예외 클래스의 계층구조 | + | try { |
- | ===== 예외 발생시키기 ===== | + | // 예외가 발생할 가능성이 있는 문장들을 넣는다. |
- | ===== 예외의 | + | } catch (Exception1 e1) { |
- | ===== finally블럭 ===== | + | // Exception1이 |
- | ===== 메서드에 예외 선언하기 | + | } catch (Exception2 e2) { |
- | ===== 예외 되던지기 ===== | + | // Exception2이 발생했을 경우, 이를 처리하기 |
- | ===== 사용자정의 예외 만들기 ===== | + | ... |
+ | } catch (ExceptionN eN) { | ||
+ | // ExceptionN이 발생했을 경우, 이를 처리하기 위한 문장을 적는다. | ||
+ | } | ||
+ | </ | ||
+ | * [예제 8-1] / | ||
+ | class ExceptionEx1 { | ||
+ | public static void main(String args) { | ||
+ | try { | ||
+ | try { } catch (Exception e) { } | ||
+ | } catch (Exception e) { | ||
+ | try { } catch (Exception e) { } // 컴파일 에러 발생 !!! | ||
+ | } // try-catch 의 끝 | ||
+ | | ||
+ | try { | ||
+ | | ||
+ | } catch (Exception e) { | ||
+ | | ||
+ | } // try-catch 의 끝 | ||
+ | | ||
+ | // main메서드의 끝 | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * [예제 8-2] / | ||
+ | class ExceptionEx2 { | ||
+ | public static void main(String[] args) { | ||
+ | int number = 100; | ||
+ | int result = 0; | ||
+ | | ||
+ | for( int i = 0 ; i < 10 ; ++i ) { | ||
+ | result = number / (int)(Math.random() * 10); // 7번째 라인, 예외 발생 | ||
+ | System.out.println(result); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * 그러면, ArithmeticException을 처리하는 예제를 살펴보자. \\ [예제 8-3] / | ||
+ | class ExceptionEx3 { | ||
+ | public static void main(String[] args) { | ||
+ | int number = 100; | ||
+ | int result = 0; | ||
+ | | ||
+ | for( int i = 0 ; i < 10 ; ++i ) { | ||
+ | try { | ||
+ | result = number / (int)(Math.random() * 10); // 7번째 라인, 예외 발생 | ||
+ | System.out.println(result); | ||
+ | } catch (ArithmeticException e) { | ||
+ | System.out.println(" | ||
+ | } // try-catch 의 끝 | ||
+ | } // for 의 끝 | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== try-catch문에서의 흐름 ===== | ||
+ | * try블럭 내에서 예외가 발생한 경우, | ||
+ | - 발생한 예외와 일치하는 catch블럭이 있는지 확인한다. | ||
+ | - 일치하는 catch블럭을 찾게 되면, 그 catch블럭 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 만일 일치하는 catch블럭을 찾지 못하면, 예외는 처리되지 못한다. | ||
+ | * try블럭 내에서 예외가 발생하지 않은 경우, | ||
+ | - catch블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다. | ||
+ | * [예제 8-4] / | ||
+ | class ExceptionEx4 { | ||
+ | public static void main(String[] args) { | ||
+ | System.out.println(1); | ||
+ | System.out.println(2); | ||
+ | | ||
+ | try { | ||
+ | System.out.println(3); | ||
+ | System.out.println(4); | ||
+ | } catch (Exception e) { | ||
+ | System.out.println(5); | ||
+ | } // try-catch의 끝 | ||
+ | System.out.println(6); | ||
+ | | ||
+ | // main메서드의 끝 | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * [예제 8-4] / | ||
+ | class ExceptionEx5 { | ||
+ | public static void main(String[] args) { | ||
+ | System.out.println(1); | ||
+ | System.out.println(2); | ||
+ | | ||
+ | try { | ||
+ | System.out.println(3); | ||
+ | System.out.println(0/ | ||
+ | System.out.println(4); | ||
+ | } catch (ArithmeticException ae) { | ||
+ | System.out.println(5); | ||
+ | } // try-catch의 끝 | ||
+ | System.out.println(6); | ||
+ | | ||
+ | // main메서드의 끝 | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== 예외 클래스의 계층구조 ===== | ||
+ | * 예외클래스 계층도 < | ||
+ | Object --- Throwable -+- Error -+- OutOfMemoryError | ||
+ | | | | ||
+ | | +- ... | ||
+ | | | ||
+ | +- Exception -+- IOException | ||
+ | | | ||
+ | +- ... | ||
+ | | | ||
+ | +- RuntimeException | ||
+ | </ | ||
+ | * 예외클래스는 다음과 같이 두 개의 그룹으로 나눠질 수 있다. | ||
+ | - RuntimeException클래스와 그 자손클래스들 | ||
+ | - Exception클래스와 그 자손클래스들 | ||
+ | * Exception클래스와 RuntimeException클래스 중심의 상속게층도 < | ||
+ | Exception -+- IOException | ||
+ | | | ||
+ | +- ClassNotFoundException | ||
+ | | | ||
+ | +- ... | ||
+ | | | ||
+ | +- RuntimeException -+- ArithmeticException | ||
+ | | | ||
+ | +- ClassCastException | ||
+ | | | ||
+ | +- NullPointException | ||
+ | | | ||
+ | +- ... | ||
+ | | | ||
+ | +- IndexOutBoundsException | ||
+ | </ | ||
+ | - RuntimeException클래스들 : 프로그래머의 실수로 발생하는 예외 | ||
+ | - Exception클래스들 : 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외 | ||
+ | * RuntimeException클래스들 그룹에 속하는 예외가 발생할 가능성이 있는 코드에는 예외처리를 해주지 않아도 컴파일 시에 문제가 되지 않지만, Exception클래스들 그룹에 속하는 예외가 발생할 가능성이 있는 예외는 반드시 처리를 해주어야 하며, 그렇지 않으면 컴파일 시에 에러가 발생한다. | ||
+ | * [예제 8-6] / | ||
+ | class ExceptionEx6 { | ||
+ | public static void main(String[] args) { | ||
+ | throw new Exception(); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * 위 예제에서 예외를 처리하여 정상 동작하도록 해보자. \\ [예제 8-7] / | ||
+ | class ExceptionEx7 { | ||
+ | public static void main(String[] args) { | ||
+ | try { | ||
+ | throw new Exception(); | ||
+ | } catch (Exception e) { | ||
+ | System.out.println(" | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * 아래 예제에서는 컴파일은 무사히 넘어가지만, | ||
+ | class ExceptionEx8 { | ||
+ | public static void main(String[] args) { | ||
+ | throw new RuntimeException(); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== 예외 발생시키기 ===== | ||
+ | * 키워드 throw 를 사용해서 프로그래머가 고의로 예외를 발생시킬 수 있으며, 방법은 아래의 순서를 따르면 된다. | ||
+ | - 먼저, 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든다음 <code java> | ||
+ | Exception e = new Exception(" | ||
+ | </ | ||
+ | - 키워드 throw를 이용해서 예외를 발생시킨다. <code java> | ||
+ | throw e; | ||
+ | </ | ||
+ | * [예제 8-9] / | ||
+ | class ExceptionEx9 { | ||
+ | public static void main(String[] args) { | ||
+ | try { | ||
+ | Exception e = new Exception(" | ||
+ | throw e; // 예외를 발생시킴. | ||
+ | // throw new Exception(" | ||
+ | } catch (Exception e) { | ||
+ | System.out.println(" | ||
+ | e.printStackTrace(); | ||
+ | } | ||
+ | System.out.println(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== 예외의 발생과 catch블럭 ===== | ||
+ | * 첫 번째 catch블럭부터 차례로 내려가면서 catch블럭의 괄호()내에 선언된 참조변수의 종류와 생성된 예외클래스의 인스턴스에 **'' | ||
+ | * 검사결과가 true인 catch블럭을 찾게 되면 블럭에 있는 문장들을 모두 수행한 후에 try-catch문을 빠져나가고 예외는 처리되지만, | ||
+ | * 모든 예외 클래스는 Exception클래스의 자손이므로, | ||
+ | * [예제 8-10] / | ||
+ | class ExceptionEx10 { | ||
+ | public static void main(String[] args) { | ||
+ | System.out.println(1); | ||
+ | System.out.println(2); | ||
+ | try { | ||
+ | System.out.println(3); | ||
+ | System.out.println(0/ | ||
+ | System.out.println(4); | ||
+ | } catch (Exception e) { // ArithmeticException대신 Exception을 사용. | ||
+ | System.out.println(5); | ||
+ | } | ||
+ | System.out.println(6); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * [예제 8-11] / | ||
+ | class ExceptionEx11 { | ||
+ | public static void main(String[] args) { | ||
+ | System.out.println(1); | ||
+ | System.out.println(2); | ||
+ | try { | ||
+ | System.out.println(3); | ||
+ | System.out.println(0/ | ||
+ | System.out.println(4); | ||
+ | } catch (ArithmeticException ae) { | ||
+ | if(ae instanceof ArithmeticException) | ||
+ | System.out.println(" | ||
+ | System.out.println(" | ||
+ | } catch (Exception e) { // ArithmeticException을 제외한 모든 예외가 처리된다. | ||
+ | System.out.println(5); | ||
+ | } | ||
+ | System.out.println(6); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * 예외가 발생했을 때 생성되는 예외클래스의 인스턴스에는 발생한 예외에 대한 정보가 담겨져 있으며, getMessage()와 printStackTrace()를 통해서 이 정보들을 얻을 수 있다. | ||
+ | - printStackTrace() : 예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다. | ||
+ | - getMessage() : 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다. | ||
+ | * [예제 8-12] / | ||
+ | class ExceptionEx12 { | ||
+ | public static void main(String[] args) { | ||
+ | System.out.println(1); | ||
+ | System.out.println(2); | ||
+ | try { | ||
+ | System.out.println(3); | ||
+ | System.out.println(0/ | ||
+ | System.out.println(4); | ||
+ | } catch (ArithmeticException ae) { | ||
+ | ae.printStackTrace(); | ||
+ | System.out.println(" | ||
+ | } | ||
+ | System.out.println(6); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * 그리고 예외 정보를 파일로 저장할 수도 있다. \\ [예제 8-13] / | ||
+ | import java.io.*; | ||
+ | class ExceptionEx13 { | ||
+ | public static void main(String[] args) { | ||
+ | PrintStream ps = null; | ||
+ | FileOutputStream fos = null; | ||
+ | | ||
+ | try { | ||
+ | fos = new FileOutputStream(" | ||
+ | ps = new PrintStream(fos); | ||
+ | | ||
+ | System.out.println(1); | ||
+ | System.out.println(2); | ||
+ | System.out.println(3); | ||
+ | System.out.println(0/ | ||
+ | System.out.println(4); | ||
+ | } catch (ArithmeticException ae) { | ||
+ | ae.printStackTrace(ps); | ||
+ | ps.println(" | ||
+ | System.out.println(" | ||
+ | } | ||
+ | System.out.println(6); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== finally블럭 ===== | ||
+ | * finally블럭은 try-catch문과 함께 예외의 발생여부와 상관없이 실행되어야할 코드를 포함시킬 목적으로 사용된다. | ||
+ | * try-catch문의 끝에 선택적으로 덧붙여 사용할 수 있으며, try-catch-finally의 순으로 구성된다. <code java> | ||
+ | try { | ||
+ | // 예외가 발생할 가능성이 있는 문장들을 넣는다. | ||
+ | } catch (Exception1 e1) { | ||
+ | // 예외처리를 위한 문장을 적는다. | ||
+ | } finally { | ||
+ | // 예외의 발생여부에 관계없이 항상 수행되어야 하는 문장들을 넣는다. | ||
+ | // finally블럭은 try-catch문의 맨 마지막에 위치해야한다. | ||
+ | } | ||
+ | </ | ||
+ | * [예제 8-15] / | ||
+ | class FinallyTest { | ||
+ | public static void main(String[] args) { | ||
+ | try { | ||
+ | startInstall(); | ||
+ | copyFiles(); | ||
+ | deleteTempFiles(); | ||
+ | } catch (Exception e) { | ||
+ | e.printStackTrace(); | ||
+ | deleteTempFiles(); | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | static void startInstall() { | ||
+ | // 프로그램 설치에 필요한 준비를 하는 코드를 적는다. | ||
+ | } | ||
+ | | ||
+ | static void copyFiles() { | ||
+ | // 파일들을 복사하는 코드를 적는다. | ||
+ | } | ||
+ | | ||
+ | static void deleteTempFiles() { | ||
+ | // 임시파일들을 삭제하는 코드를 적는다. | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * [예제 8-16] / | ||
+ | class FinallyTest2 { | ||
+ | public static void main(String[] args) { | ||
+ | try { | ||
+ | startInstall(); | ||
+ | copyFiles(); | ||
+ | } catch (Exception e) { | ||
+ | e.printStackTrace(); | ||
+ | } finally { | ||
+ | deleteTempFiles(); | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | static void startInstall() { | ||
+ | // 프로그램 설치에 필요한 준비를 하는 코드를 적는다. | ||
+ | } | ||
+ | | ||
+ | static void copyFiles() { | ||
+ | // 파일들을 복사하는 코드를 적는다. | ||
+ | } | ||
+ | | ||
+ | static void deleteTempFiles() { | ||
+ | // 임시파일들을 삭제하는 코드를 적는다. | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * 특히, try나 catch 블럭의 문장 수행중에 return을 만나도 finally블럭의 문장들은 수행된다. \\ [예제 8-17] / | ||
+ | class FinallyTest3 { | ||
+ | public static void main(String[] args) { | ||
+ | // method1()은 static메서드이므로 인스턴스 생성없이 직접 호출이 가능하다. | ||
+ | FinallyTest3.method1(); | ||
+ | System.out.println(" | ||
+ | } | ||
+ | | ||
+ | static void method1() { | ||
+ | try { | ||
+ | System.out.println(" | ||
+ | return; | ||
+ | } catch (Exception e) { | ||
+ | e.printStatckTrace(); | ||
+ | } finally { | ||
+ | System.out.println(" | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== 메서드에 예외 선언하기 ===== | ||
+ | * 예외를 처리하는 방법에는 지금까지 배워 온 try-catch문을 사용하는 것 이외에, 예외를 메서드에 선언하는 방법이 있다. | ||
+ | * 메서드에 예외를 선언하려면, | ||
+ | void method() throws Exception1, Exception2, ... ExceptionN { | ||
+ | // 메서드의 내용 | ||
+ | } | ||
+ | </ | ||
+ | * 사실, 예외를 메서드의 throws에 명시하는 것은 예외를 처리하는 것이 아니라, 자신(예외가 발생할 가능성이 있는 메서드)을 호출한 메서드에게 예외를 전달하여 예외처리를 떠맡기는 것이다. | ||
+ | * [예제 8-18] / | ||
+ | class Exception18 { | ||
+ | public static void main(String[] args) throws Exception { | ||
+ | method1(); // 같은 클래스내의 static 멤버이므로 객체생성없이 직접 호출가능. | ||
+ | } | ||
+ | | ||
+ | static void method1() throws Exception { | ||
+ | method2(); | ||
+ | } | ||
+ | | ||
+ | static void method2() throws Exception { | ||
+ | throw new Exception(); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | - 예외가 발생했을 때, 모두 3개의 메서드(main, | ||
+ | - 예외가 발생한 곳은 제일 위줄에 있는 method2()라는 것과 | ||
+ | - main메서드가 method1()를, | ||
+ | * 결국, 어디서 든 간에 반드시 try-catch문을 사용해서 예외처리를 해주어야 정상적인 종료를 할 수 있을 것이다. | ||
+ | ===== 예외 되던지기 ===== | ||
+ | * 하나의 예외에 대해서 예외가 발생한 메서드와 호출한 메서드, 양 쪽에서 처리하도록 할 수 있다. | ||
+ | * 이것은 예외를 처리한 수에 인위적으로 다시 발생시키는 방법을 통해서 가능한데, | ||
+ | * [예제 8-23] / | ||
+ | class ExceptionEx23 { | ||
+ | public static void main(String[] args) { | ||
+ | try { | ||
+ | method1(); | ||
+ | } catch (Exception e) { | ||
+ | System.out.println(" | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | static void method1() throws Exception { | ||
+ | try { | ||
+ | throw new Exception(); | ||
+ | } catch (Exception e) { | ||
+ | System.out.println(" | ||
+ | throw e; // 다시 예외를 발생시킨다. | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== 사용자정의 예외 만들기 ===== | ||
+ | * 기존의 정의된 예외 클래스 외에 필요에 따라 프로그래머가 새로운 예외 클래스를 정의하여 사용할 수 있다. 보통 Exception클래스로부터 상속받는 클래스를 만들지만, | ||
+ | class MyException extends Exception { | ||
+ | MyException(String msg) { // 문자열을 매개변수로 받는 생성자 | ||
+ | super(msg); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * 필요하다면 멤버번수를 추가할 수 있다. <code java> | ||
+ | class MyException extends Exception { | ||
+ | // 에러 코드 값을 저장하기 위한 필드를 추가했다. | ||
+ | private final int errorCode = 100; | ||
+ | | ||
+ | MyException(String msg) { // 생성자 | ||
+ | super(msg); | ||
+ | } | ||
+ | | ||
+ | public int getCode() { // 에러 코드를 얻을 수 있는 메서드도 추가했다. | ||
+ | return errorCode; | ||
+ | } | ||
+ | } | ||
+ | </ |