Exception (에러처리)
try, catch, finally, throw, throws
프로그램을 만들다가 예기치 않게 에러가 발생할수 있습니다. 아니면, 어떤에러가 발생할수도 있다고 예상할 수도 있습니다. 그것도 아니라면, 일부러 에러를 발생시킬 수도 있습니다.
이번 Exception 에러처리 부분을 공부하면서, 느낀점은 자바는 C언어보다 더 안전하게 프로그래밍을 할수 있도록 되있는 것 같습니다. 어떤 중요한 작업을 해야하는 부분에서는 Exception 에러처리를 의무적으로 사용을 해야지만 동작을 하는 곳까지 있습니다. 입출력(네트웍 입출력, 데이터베이스 입출력, 파일 입출력, 메모리 입출력 등)을 구현코드에 집어넣으려고할때 꼭 try, catch를 써야합니다. 안쓰면, 모든걸 제대로 작성했다고해도, 단순히, try, catch문을 쓰지 않았다고 에러가 납니다. ^_^
런타임 에러 (Runtime Error)
에러 처리 하는데, 컴파일 도중 나오는 컴파일 에러(Comile Error), 실행 도중 나오는 런타임 에러(Runtime Error) 두 종류가 있습니다. 여기서는 쫌 귀찬게 에러를 잡아줘야 하는 런타임 에러 방지 방법을 알아볼 것입니다. 런타입 에러의 경우, 중요한건! 실행 중에 에러가 발생했는데, catch로 예외처리를 하지 않았다면 실행도중 중지될 것입니다.
이번 Exception 장에서 필수 키워드는 try, catch, finally, throw, throws 이렇게 5가지 입니다.
try, catch, finally
먼저, try, catch, finally 먼저 보겠습니다.
try는 에러가 발생할 여지가 있는 코드를 작성하면 됩니다. catch는 try와 한쌍이 되서 사용되어야 하는데, try의 { .. } 괄호 안에서 에러가 발생하면 해당 에러를 catch 문으로 잡아서 처리할 수가 있습니다. catch 문은 여러 개로 사용될 수 있습니다. finally는 사용해도 되고 안해도 되는데, 마지막에 무조건 처리할 코드가 있을 떄 사용됩니다.
if문 |
try, catch문 |
if(조건){ |
try { // 에러발생하면, catch로 이동 // 발생하면
여기로 이동 // 발생하면
여기로 이동 // 여기는 지나감 |
이해가 쫌 더 빨리 되게 위해 if문이랑 비교해봤습니다. 생긴게 좀 비슷하죠?^_^ 프로그램 실행 영역을 try로 감싸주기만 하고, 거기서 발생하는 에러를 catch로 잡아서 처리만 해주면 됩니다.
아래 몇 가지 런타입 에러의 상황을 예시로 사용법을 알아보겠습니다. 빨간색은 일부러 에러를 발생시킨 부분입니다.
예시 1)
NullPointerException 참조할 메모리가 없다는 오류 |
설명: 주황색 코드(try, catch)가 없다면, 실행 중에 에러가 발생합니다. |
public class TryCatchMain{ public static void main(String[] args){ try{ String str = null; System.out.println(str.length()); } catch(NullPointerException e){ System.out.println(e.toString() + " 에러 발생"); System.out.println("에러처리 루틴 실행"); } System.out.println("프로그램 종료"); } |
실행결과: java.lang.NullPointerException 에러발생 에러처리 루틴 실행 프로그램 종료 |
예시 2)
ArrayIndexOutOfBoundsException 배열 범위가 넘어갔다는 오류 |
설명: 주황색 코드(try, catch)가 없다면 실행 중에 에러가 발생하고, 파란색 코드(finally)는 catch 구문으로 들어오더라도 마지막에 처리하고 싶은 코드가 있다면 여기에 넣어서 사용하면 유용합니다. |
public class BasicException { public static void main(String args[]) { try{ int[] ar = new int[]{0, 100, 200, 300}; for(int i=0; i<ar.length+1; i++){ System.out.println("ar["+i+"]=" + ar[i]); } } catch(ArrayIndexOutOfBoundsException e) { System.out.println(e.getMessage()); System.out.println(e.toString()); e.printStackTrace(); return; } finally{ System.out.println("try, catch상관없이 여기로!"); } } |
실행결과: ar[0]=0 |
예시 3)
FileNotFoundException & ArrayIndexOutOfBoundsException 파일을 찾을 수 없다는 오류 & 배열 범위가 넘어갔다는 오류 |
설명: 주황색 코드(try, catch)가 없다면 실행 중에 에러가 발생하고. 초록색(catch(Exception e)) 코드는 try 에서 발생하는 모든 예외(Exception)에 대해 catch가 받지 못한 에러들은 여기서 전부 받아서 처리한다. 혹시라도 직접 작성한 catch문으로는 부족하다고 생각하면 마지막에 Exception을 catch로 잡는 아래처럼 작성하기도 한다. 이게 가능한 이유는, Java에서 발생하는 모든 에러들은 Exception 클래스를 상속받았기 때문이다. (=업캐스팅, Upcastring) |
import java.io.*; public class LevelCatchMain{ public static void main(String[] args){ try{ FileReader f = new FileReader("Hi.java"); String s = null; System.out.println(s.toString()); } catch(FileNotFoundException e1){ System.out.println("FileNotFoundException:" + e1); } catch(ArrayIndexOutOfBoundsException e2){ System.out.println(e2); } catch(Exception e3){ System.out.println(e3); } } } |
실행화면: java.lang.NullPointerException |
※ 참고
e.getMessage() : 에러 이벤트와 함께 들어오는 메시지를 출력한다.
e.toString() : 에러 이벤트의 toString()을 호출해서 간단한 에러 메시지를 확인한다.
e.printStackTrace() : 에러 메시지의 발생 근원지를 찾아서 단계별 에러를 출력한다.
throw, throws
이번에는 throw, throws를 보겠습니다.
throw는 에러를 일부러 발생시키는 것입니다. throws는 에러를 바로 처리하기 귀찬을 때, 나중에 처리할수 있도록 미룰 때 사용하는 것입니다. 이번에도 몇가지 예시를 살펴보겠습니다.
예시 1)
throw 직접 오류를 발생 |
설명: 빨간색으로 표시한 부분을 보면 일부러 오류를 발생시켰습니다. 여기서는 throw 사용방법을 보기 위해서 구~지 throw를 사용해서 오류를 발생시킨 것입니다. 직접 발생시킨 오류도 앞에서 설명한 것처럼 catch문으로 잡을 수 있습니다. |
public class UseThrowMain { |
실행화면: 정보:일부러
에러 발생 |
예시 2)
throws 에러를 호출하는 쪽으로 넘겨버림 |
설명: makeURL 함수에서 에러가 발생했지만, makeURL 함수 안에서 try, catch문으로 처리하지 않고 호출하는 상위 쪽으로 넘겨버렸습니다. 그래서, 만약에 makeURL 내에서 에러가 발생하면 makeURL을 호출하고 있는 main함수 내에서 에러를 처리해주어야 합니다. 아래 예시는 일부러 makeURL 안에서 URL 포멧이 틀렸을 때 발생하는 오류인 MalformedURLException가 발생하도록 URL을 이상하게 적어서 실행했습니다. |
import java.net.*; |
실행결과: java.net.MalformedURLException:
unknown protocol: htttttp |
이렇게, try, catch, finally, throw, throws에 대해 알아봤습니다. 작은 클래스 한두개를 작성할 때는 이 키워드를 잘 사용하지 않고, 사용하더라도 대충 사용하는 경우가 많습니다. 하지만, 코드가 점점 커지고 하나의 프로젝트 규모가 될 정도로 커지면 예외처리는 엄청나게 중요해집니다. 개발자의 생산성과 속도로 직결되는 부분 중 하나입니다. 따라서, 처음부터 조금씩 조금씩 잘 사용하도록 습관을 들이는게 중요하다고 생각합니다.^_^