프로그래밍 오류(에러)는 발생 시점에 따라 컴파일타임 에러, 런타임 에러, 시스템 에러 세 가지로 구분할 수 있다.
컴파일 에러
- 소스 컴파일 시에 발생하며 주로 문법적인 에러이다. 에러가 발생된 소스 코드를 수정하여야 한다.
런타임 에러
- 프로그램 실행 도중에 발생하며, 잘못된 값의 입력 등 수행할 수 없는 작업을 시도할 경우에 발생한다. 소스 코드로 에러 발생 구문을 수정하여야 한다.
- 시스템 에러
- 컴퓨터 시스템 상에 발생하는 오동작에 의한 에러로 정정, 메모리 부족 등 소스 코드로는 해결할 수 없는 장비 또는 운영체제 관련 에러이다. 소스 코드 수정으로는 해결할 수 없다.
자바는 런타임 에러를 '에러(error)'와 예외(exception)'으로 구분한다. 에러는 프로그램 소스 코드로 해결할 수 없는 경우를 말하며 복구할 수 없는 심각한 경우이다. 예외는 소스 코드로 해결할 수 있는 에러를 말하며 발생하더라도 해결할 수 있다.
자바는 예외를 크게 두 가지로 구분하였는데, RuntimeException이나 그 후손들은 Unchecked Exception 이라 하여 소스 코드상에서 처리하지 않아도 되는 예외로, 그 외의 예외들을 Checked Exception 이라 하여 반드시 소스 코드로 예외 처리(Exception Handling)를 해주어야 하는 예외로 구분해 두었다.
예외 처리 구문은 크게 세 가지로 제공되며, 예외를 직접 처리할 때 사용하는 try - catch - finally 구문, 예외를 이전 호출 위치로 넘기는 throws 구문, 자동으로 close 처리를 해주는 try with resource 문이 있다.
예외가 발생되면 프로그램은 비정상적으로 종료하게 된다. 만약 프로그램이 종료되지 않고 실행의 흐름을 바꾸고자 한다면 try ~ catch 문으로 직접 예외를 처리해 주면 된다.
try ~ catch 문 맨 마지막에 사용되는 finally 구문은 예외가 발생하든 발생하지 않든 무조건 구동되어야 하는 코드를 작성하는 영역이다.try { // 예외 발생 가능성이 있거나, 예외를 반드시 처리해야 하는 코드 작성부 } catch (처리할 예외클래스명 객체 1) { // 예외 상황 1에 대한 처리 코드 } catch (처리할 예외클래스명 객체 2) { // 예외 상황 2에 대한 처리 코드 } finally { // 예외 발생으로 try { } 안의 코드가 중단되더라도 반드시 실행해야 하는 코드 }
하나 이상의 catch 문을 사용할 경우에는 반드시 처리할 예외클래스들이 상속관계를 고려하여 최하위 후손 클래스부터 기술해 주어야 한다.
발생한 예외에 대한 정보를 확인하려면 에러 객체를 직접 출력하거나(예외객체.toString()) 메시지를 출력하거나 (예외객체.getMessage()) 또는 실행 흐름상의 예외 발생 단계를 추적하여 출력하는 (예외객체.printStackTrace()) 코드를 추가할 수도 있다.
test.exception.TestException1.java
01 package test.exception;
02
03 public class TestException1 {
04 public static void main(String[] args) {
05 int arr[] = new int[3];
06
07 try {
08 for(int i = 0; i < arr.length; i++)
09 arr[i] = i;
10
11 for(int i = 0; i <= arr.length; i++)
12 System.out.println(arr[i]);
13 } catch(ArrayIndexOutOfBoundsException e) {
14 System.out.println("예외 : 사용불가 인덱스 접근");
15 e.printStackTrace(); // System.out.println(e);
16 } finally {
17 System.out.println("반드시 수행하는 코드");
18 }
19 }
20 }
------
0
1
2
예외 : 사용불가 인덱스 접근
java.lang.ArrayIndexOutOfBoundsException:3
반드시 수행하는 코드
at test.Test.main(Test.java:12)
이 방법을 사용하면 해당 메소드 안에서 발생한 예외 처리에 대한 책임을 메소드를 호출한 쪽으로 떠넘길 수 있다. 컴파일 시에는 문제가 없지만 예외 발생 시에 호출하는 코드에서 예외를 처리하지 못 한다면 프로그램은 비정상 종료를 하게 된다. 호출하는 입장에서 선언된 예외를 보고 발생할 수 있는 예외를 미리 파악할 수 있고 또한 반드시 처리해야 하므로 프로그램을 견고하게 한다.
test.exception.TestThrows.java
01 package test.exception;
02
03 import java.io.IOException;
04
05 public class TestThrows {
06 public static void main(String[] args) {
07 IOSample test = new IOSample();
08 try {
09 test.input();
10 test.output();
11 } catch (IOException e) {
12 e.printStackTrace();
13 } catch (ArrayIndexOutOfBoundsException e) {
14 e.printStackTrace();
15 }
16 }
17 }
test.exception.IOSample.java
01 package test.
02
03
04
05
06
07
08
09
10
11
12
13