7.2.1 에러처리란?
보통 에러는 컴파일 타임의 에러와 실행 타임의 에러로 구분되어지고 있습니다. 컴파일 타임의 에러는 문법적인 에러이며, 이것은 자바 구문상의 에러입니다. 모든 에러가 컴파일 타임에 발견될 수 있는 것은 아닙니다. 사실 컴파일 타임의 에러야 어떤 식으로든 찾으면 됩니다. 대부분 기본적인 문법을 지키지 않아서 발생하는 에러이기 때문에 어렵지 않게 찾을 수 있습니다. 하지만 컴파일이 되었다 하더라도 실행하는 동안에 에러가 발생할 수도 있습니다. 실행 타임의 에러는 프로그램 로직(Logic)상의 오류이기 때문에 그렇게 만만한 것은 아닙니다.
▣ 컴파일 타임 오류(Compile-Time Error)
◈ 자바의 문법적 오류로 컴파일이 되지 않는 구문상의 오류
▣ 실행 타임 오류(Run-Time Error)
◈ 컴파일은 되지만 실행이 되지 않는 로직(Logic)상의 오류
이 장에서 학습하는 내용은 문법적인 오류를 위한 것이 아니라 프로그램 로직(Logic)상의 오류를 말합니다. 먼저 Exception의 의미부터 알아보도록 하죠. Exception이란 무엇일까요? Exception은 실행 타임에 발생하는 에러 이벤트(Error Event)를 의미합니다.
▣ Exception의 정의
◈ Exception은 실행 타임에 발생하는 에러 이벤트(Error Event)를 말한다.
자바에서는 에러가 발생했을 때 에러 이벤트(Error Event)라는 것이 발생합니다. 이 이벤트를 Exception이라고 합니다. 프로그램에서 에러가 발생할 때 Exception 이벤트가 발생하고, 발생된 이벤트는 프로그래머가 처리하지 않으면 곧장 가상머신으로 넘어가게 됩니다. 가상머신에서는 이 이벤트를 받았을 때 에러 이벤트의 성격에 따라서 적절한 조치를 취하게 됩니다. 대부분의 경우 프로그램을 중지시키는 루틴을 실행하게 됩니다.
그렇다면 Exception 이벤트가 가상머신에 의해서 자동으로 처리되기 전에 에러를 처리하려 할 것입니다. 실행 타임에 에러 이벤트가 발생했을 때 프로그래머가 이를 먼저 감지하기 위한 도구가 바로 try와 catch입니다.
쉬운 예를 들어보죠. 파일을 로딩하려는데 파일이 없다면 File Not Found Exception이 발생할 것입니다. 이 에러가 발생하기 전에 파일이 있는지 없는 지를 검사하는 루틴을 넣어서 프로그램한다면 절대 에러는 발생하지 않을 것입니다. 보통의 File 라이브러리들은 파일의 존재 여부를 확인하는 메서드 정도는 제공하고 있습니다. 이를 이용한다면 File Not Found Exception이 발생하기 전에 해결할 수 있습니다.
▣ 에러처리 방법 I
◈ 프로그램적으로 에러가 발생하지 않도록 완벽하게 코딩
프로그램 실행 시에 파일이 존재하지 않는다면 그리고 파일 존재 여부를 확인하는 루틴을 넣지 않았다면 File Not Found Exception은 곧장 가상머신으로 보내질 것입니다. 이 중간에 프로그래머가 File Not Found Exception을 가로채기 위해서 우선 try로 에러 감지 부분을 설정하고, 이 부분에서 에러가 감지되면 처리 루틴인 catch로 보낼 것입니다.
▣ try와 catch 블록의 사용
◈ try{
◈ //파일로딩
◈ //try 블록은 에러 감지블록
◈ }catch(FileNotFountException e){
◈ //catch 블록은 에러 처리블록
◈ }
▣ 에러처리 방법 II
◈ try와 catch를 이용해서 프로그래머가 에러를 감지해서 처리
에러가 발생하지 않도록 완벽하게 코딩하는 것과 try, catch 루틴을 사용하는 것은 아주 미세한 차이가 있습니다. 예전의 방식은 try, catch 보다는 프로그래머가 직접 처리하는 것을 더 선호했습니다. 하지만 자바에서는 try와 catch를 필요한 곳에 의무적으로 사용하도록 하고 있습니다.
▣ 참고
◈ 위의 경우에 설명을 위해서 사용자가 파일의 유무를 확인하는 에러처리 기법을 소개하고 있지만, 자바에서는 파일을 다룰 때 try, catch를 의무적으로 사용해야 합니다.
▣ 에러처리의 의무화
◈ 자바에서는 에러가 발생할 가능성이 높은 곳에 try와 catch의 사용이 의무적이다.
표준 C++에서는 try, catch를 사용하든 하지 않든 그것은 전적으로 프로그래머의 책임이었습니다. 프로그래머가 필요하다고 생각될 때 try, catch를 이용하면 됐습니다. 하지만 자바에서는 실행 타임에 에러가 발생할 가능성이 있는 곳이면 컴파일러 차원에서 의무적으로 에러처리 루틴을 붙여주도록 하고 있습니다. 즉 에러가 발생할 가능성이 높은 곳은 무조건 try와 catch를 붙여야만 합니다. 에러처리 루틴을 컴파일러 차원에서 사용하도록 강요하는 것입니다. C나 C++에서는 컴파일러 차원에서 체크하지 않았는데, 자바에서는 에러 발생 확률이 높은 곳은 반강제적으로 넣도록 하고 있습니다. 다음과 같이 코딩하면 컴파일할 때 에러가 발생합니다.
『chap07\ErrorMain.java』
ⓙ───────────────────────────────────────
/**
FileReader는 의무적으로 FileNotFoundException을
처리해 주어야 하지만 예외처리를 하지 않은 경우
**/
import java.io.*;
public class ErrorMain{
public static void main(String[] args) {
FileReader fr = new FileReader("ErrorMain.java");
} //end of main
} //end of ErrorMain class
//㉶--------------------------------------------㉳
/***
C:\javasrc\chap07>javac ErrorMain.java
ErrorMain.java:4: unreported exception java.io.FileNotFoundException;
must be caught or declared to be thrown
FileReader fr = new FileReader("ErrorMain.java");
^
1 error
***/
───────────────────────────────────────ⓑ
위의 에러는 FileReader라는 것을 사용하면서도 에러처리 루틴을 삽입하지 않았기 때문에 발생하는 에러입니다. 컴파일러 차원에서 에러처리 루틴이 있는지 없는지 검사하기 때문에 FileReader라는 것을 사용할 때는 반드시 try와 catch를 이용해서 FileNotFoundException 처리를 해주어야 합니다. 위의 코드는 다음과 같이 수정한다면 컴파일을 무사히 통과할 것입니다.
『chap07\ErrorMain2.java』
ⓙ───────────────────────────────────────
/**
try, catch를 이용해서 FileNotFoundException을 처리한 경우
**/
import java.io.*;
public class ErrorMain2{
public static void main(String[] args){
try{
FileReader fr = new FileReader("ErrorMain.java");
//fr을 이용해서 작업
}catch(FileNotFoundException e){
System.out.println(e);
}
} //end of main
} //end of ErrorMain2 class
//㉶--------------------------------------------㉳
/***
C:\javasrc\chap07>javac ErrorMain2.java
C:\javasrc\chap07>java ErrorMain2
***/
───────────────────────────────────────ⓑ
어디에 try-catch를 붙여야 할 지는 컴파일 에러를 통해서 컴파일러가 친절히 알려 줄 것입니다. 대부분의 경우 입출력에 관계된 곳이면 에러처리 루틴을 무조건 붙인다고 생각하시면 됩니다. 의무적으로 에러 루틴을 사용해야 하는 입출력 작업은 다음과 같습니다.
▣ 입출력 작업을 할 때 에러처리를 붙여야 하는 곳
◈ 네트웍 입출력
◈ 데이터베이스 입출력
◈ 파일 입출력
◈ 메모리 입출력
이 이외에도 입출력과 관련된 곳이면 에러 루틴이 필수적입니다. 사실 위의 목록을 제외한다면 프로그램이 별 의미가 없죠.
▣ 에러처리 루틴의 의무화
◈ 에러가 자주 발생하는 곳에는 컴파일러 차원에서 에러처리 루틴을 요구하기 때문에 의무적으로 에러처리 루틴을 넣어야 한다.
프로그램 동작시 발생하는 에러가 어디서 발생했는지 찾기란 상당히 어렵습니다. 실행 타임의 에러를 미연에 방지하는 차원에서 에러처리 루틴을 의무화한 것입니다. 이렇게 함으로써 실행 타임의 에러는 줄이고 더욱 튼튼한 프로그램 작성을 유도하고 있는 것입니다.
▣ 에러처리 구문을 사용하는 이유
◈ 실행 타임의 에러를 미연에 방지하기 위해서
◈ 에러 이벤트가 발생했을 때 발생한 위치의 확인을 위해서
◈ 에러 이벤트가 발생했을 때 적절하게 대처하기 위해서
에러가 발생했을 때 발생한 이벤트를 처리해 줄 수 있도록 하는 것이 바로 에러처리 구문입니다. 에러처리의 사용법은 간단하지만 잘못 사용하면 의미가 없어져 버릴 수도 있습니다. 적절하게 잘 사용하면 아주 매력적인 프로그램을 작성할 수 있습니다.