어서와 Java는 처음이지! 제14장 오류처리하기
디버깅 우리가 사는 세상은 완벽하지 않다!
오류 메시지를 분석한다. 오류 메시지에서 많은 내용을 알 수 있다.
디버깅 디버거를 사용하면 프로그램에서 쉽게 오류를 감지하고 진단할 수 있다. 디버거는 중단점을 설정하여서 프로그램의 실행을 제어할 수 있으며 문장 단위로 실행하거나 변수의 값을 살펴볼 수 있다.
이클립스에서 디버깅
이클립스에서 디버깅
이클립스의 디버깅 명령어
예외처리 오류가 발생했을 때 오류를 사용자에게 알려주고 모든 데이터를 저장하게 한 후에 사용자가 우아하게(gracefully) 프로그램을 종료할 수 있도록 하는 것이 바람직하다
예외란? 예외(exception): 잘못된 코드, 부정확한 데이터, 예외적인 상황에 의하여 발생하는 오류 (예) 0으로 나누는 것과 같은 잘못된 연산이나 배열의 인덱스가 한계를 넘을 수도 있고, 디스크에서는 하드웨어 에러가 발생할 수 있다.
try-catch 블록
예외의 예 public class BadIndex { public static void main(String[] args) { int[] array = new int[10]; for (int i = 0; i < 10; i++) array[i] = 0; int result = array[12]; System.out.println("과연 이 문장이 실행될까요?"); } 실행되지 않음!
try-catch 블록으로 예외 처리 public class BadIndex2 { public static void main(String[] args) { int[] array = new int[10]; for (int i = 0; i < 10; i++) array[i] = 0; try { int result = array[12]; } catch (ArrayIndexOutOfBoundsException e) { System.out.println("배열의 인덱스가 잘못되었습니다."); } System.out.println("과연 이 문장이 실행될까요?");
try/catch 블록에서의 실행 흐름
finally 블록
try-with-resources 문장 try-with-resources 문장은 Java SE 7버전부터 추가되었다.
예제 ArrayList<String> list = new ArrayList<String>(); list.add(“item1”); list.add(“item2”); list.add(“item3”); try (PrintWriter output = new PrintWriter("myoutput.txt")) { for (String s : list) { output.println(s.toLowerCase()); }
예외의 종류
예외의 종류
다형성과 예외 다형성의 원칙에 따라 상위 클래스의 참조 변수는 하위 클래스의 객체를 참조할 수 있다. 특히 이것은 catch 블록에서 예외를 잡을 때 유용하다.
다형성과 예외 try { getInput(); // 예외를 발생하는 메소드 } catch(NumberException e) { catch(Exception e) { //Exception의 모든 하위 클래스를 잡을 수 있으나 분간할 수 없다.!
다형성과 예외 try { getInput(); } catch(TooSmallException e) { catch(NumberException e) { //TooSmallException을 제외한 나머지 예외들이 잡힌다. try { getInput(); } catch(NumberException e) { //모든 NumberException이 잡힌다. catch(TooSmallException e) { //아무 것도 잡히지 않는다!
예외와 메소드 throws를 사용하여, 다른 메소드한테 예외 처리를 맡길 수 있다.
예제 public void writeList() throws IOException { PrintWriter = new PrintWriter(new FileWriter("outfile.txt")); for (int i = 0; i < SIZE; i++) out.println("배열 원소 " + i + " = " + list[i]); out.close(); }
에외를 처리하는 절차 어떤 메소드 안에서 예외가 발생하면 런타임 시스템은 그 메소드 안에 예외 처리기가 있는 지를 살핀다. 만약 그 자리에 예외 처리기가 없다면 호출 스택(call stack)에 있는 상위 메소드를 조사하게 된다.
LAB: 예외 처리하기 다음 코드의 예외를 처리하여 보자. public class Test { public static void main(String[] args) { System.out.println(readString()); } public static String readString() { byte[] buf = new byte[100]; System.out.println("문자열을 입력하시오:"); System.in.read(buf); return new String(buf); Exception in thread "main" java.lang.Error: Unresolved compilation problem: Unhandled exception type IOException at Test.readString(Test.java:9) at Test.main(Test.java:3)
SOLUTION import java.io.IOException; public class Test { public static void main(String[] args) { try { System.out.println(readString()); } catch (IOException e) { System.out.println(e.getMessage()); e.printStackTrace(); } public static String readString() throws IOException { byte[] buf = new byte[100]; System.out.println("문자열을 입력하시오:"); System.in.read(buf); return new String(buf);
에외 생성하기
예외는 throw 문장으로 생성된다. 어떤 메소드도 throw 문장을 사용하여서 예외를 생성할 수 있다. throw 문장은 하나의 인수만을 요구하는데 바로 Throwable 객체이다.
예제 public Object pop() { Object obj; if (size == 0) { throw new EmptyStackException(); } ... return obj;
예외 처리의 장점 오류 처리 코드를 정상적인 코드와 분리할 수 있다. 동일한 코드를 예외 처리를 사용하지 않는 경우와 예외 처리를 사용하는 경우로 분리하여 비교해보자.
예외 처리를 사용하지 않는 경우 errorCodeType readFile() { int errorCode = 0; 파일을 오픈한다; if (theFileIsOpen) { 파일의 크기를 결정한다; if (gotTheFileLength) { 메모리를 할당한다; if (gotEnoughMemory) { 파일을 메모리로 읽는다; if (readFailed) { errorCode = -1; } } else { errorCode = -2; errorCode = -3; ...
예외 처리를 사용하는 경우 void readFile() { try { 파일을 오픈한다; 파일의 크기를 결정한다; 메모리를 할당한다; 파일을 메모리로 읽는다; 파일을 닫는다; } catch (fileOpenFailed) { ... } catch (sizeDeterminationFailed) { } catch (memoryAllocationFailed) { } catch (readFailed) { } catch (fileCloseFailed) { }
LAB: 예외 처리하기 다음 코드의 예외를 처리하여 보자. public class ExceptionTest3 { public static void main(String args[]) { int num = Integer.parseInt("ABC"); System.out.println(num); } Exception in thread "main" java.lang.NumberFormatException: For input string: "XYZ" at java.lang.NumberFormatException.forInputString(Unknown Source) at java.lang.Integer.parseInt(Unknown Source) at numberformat.ExceptionTest3.main(ExceptionTest3.java:6)
SOLUTION public class ExceptionTest3 { public static void main(String args[]) { try { int num = Integer.parseInt("ABC"); System.out.println(num); } catch (NumberFormatException e) { System.out.println("NumberFormat 예외 발생"); }
단언 단언(assertions)은 프로그래머가 현재 시점에서 믿고 있는 내용을 다시 한 번 확인할 때 사용된다.
단언의 형식
예제 import java.util.Scanner; public class AssertionTest { public static void main(String argv[]) { Scanner input = new Scanner(System.in); System.out.print("날짜를 입력하시오: "); int date = input.nextInt(); // 날짜가 1 이상이고 31 이하인지를 검증한다. assert(date >= 1 && date <= 31) : "잘못된 날짜: " + date; System.out.printf("입력된 날짜는 %d입니다.\n", date); }
로깅 로깅(logging)이란 어딘가에 계속하여 기록을 남기는 것이다.
예제 im port java.util.logging.Logger; public class LoggingTest { public static void main(String argv[]) { String filename = "test.dat"; Logger.getGlobal().info(filename + " 파일을 오픈하였음 "); } 8월 15, 2015 1:48:39 오후 LoggingTest main 정보: test.dat 파일을 오픈하였음
Q & A