예외 처리 기본
컴파일 에러: 컴파일 할때 발생하는 에러이다.
런타임 에러: 프로그램의 실행도중에 발생하는 에러이다.
소스코드를 컴파일 하면 컴파일러가 소스코드(.java)에 대해 오타나 잘못된 구문, 자료형 체크 등의 기본적인 검사를 수행하여 오류가 있는지 알려준다. 컴파일러가 알려 준 에러들은 모두 수정해서 컴파일을 성공적으로 마치고 나면, 클래스 파일(.class)이 생성되고, 생성된 클래스 파일을 실행할 수 있게 되는 것이다.
컴파일러가 소스코드의 기본적인 사항은 컴파일시에 모두 걸러줄 수 있지만, 실행 도중에 발생할 수 있는 잠재적인 오류까지 검사할 수 없기 때문에 컴파일은 잘되었어도 실행 중에 에러에 의해서 잘못된 결과를 얻거나 프로그램이 비정상적으로 종료될 수 있다.
자바에서는 실행 시(runtime) 발생할 수 있는 프로그램 오류를 '에러'와 '예외' 두 가지로 구분하였다.
에러는 메모리 부족이나 스택오버플로우와 같이 일단 발생하면 복구할 수 없는 심각한 오류이고, 예외는 발생하더라도 수습될 수 있는 비교적 덜 심각한 것이다.
-> 에러와 예외는 모두 실행 시(runtime) 발생하는 오류이다.
1. 예외 클래스
RuntimeException 클래스들은 주로 프로그래머의 실수에 의해서 발생할 수 있는 예외들로서 자바의 프로그래밍 요소와 관계가 깊다.
--> 프로그래머의 실수로 발생하는 예외
Exception 클래스들은 주로 외부의 영향으로 발생할 수 있는 것들로서, 프로그램의 사용자들의 동작에 의해서 발생하는 경우가 많다.
--> 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외
RuntimeException 클래스들과 Exception 클래스들의 중요한 차이점은 컴파일시의 예외처리 체크여부이다. RuntimeException 클래스들 그룹에 속하는 예외가 발생할 가능성이 있는 코드에는 예외 처리를 해주지 않아도 컴파일 시에 문제가 되지 않지만, Exception 클래스들 그룹에 속하는 예외가 발생할 가능성이 있는 예외는 반드시 처리를 해주어야 하며, 그렇지 않으면 컴파일 시에 에러가 발생한다.
class ExceptionEx7
{
public static void main(String[] args)
{
throw new Exception(); // Exception을 강제로 발생시킨다.
}
}
이 예제를 작성한 후에 컴파일 하면 컴파일이 완료되지 않는다. 예외처리가 되어야 할 부분에 예외처리가 되어 있지 않다는 에러이다. 위의 결과에서 알 수 있는 것처럼, 위에서 분류한 '그 외의 Exception클래스들'이 발생할 가능성이 있는 문자들에 대해 예외처리를 해주지 않으면 컴파일 조차 되지 않는다.
따라서 위의 예제를 아래와 같이 try-catch 문으로 처리해 주어랴 컴파일이 성공적으로 이루어 질 것이다.
class ExceptionEx8 {
public static void main(String[] args)
{
try {
throw new Exception();
} catch (Exception e) {
System.out.println("Exception이 발생했습니다.");
}
} // main메서드의 끝
}
※ 주의 할점
class ExceptionEx9
{
public static void main(String[] args) {
throw new RuntimeException(); // RuntimeException을 강제로 발생시킨다.
}
}
위의 예제를 컴파일 하면, 예외를 처리하지 않았음에도 불구하고 이전의 예제와는 달리 성공적으로 컴파일이 될 것이다. 그러나 실행하면, RumtimeException이 발생하여 비정상적으로 종료될 것이다.
이 예제가 명백히 RuntimeException을 발생시키는 코드를 가지고 있고, 이에 대한 예외처리를 하지 않았음에도 불구하고 성공적으로 컴파일 되었다.
이와 같이 RuntimeException클래스들은 예외처리를 해주지 않아도 컴파일러가 문제삼지 않는 것을 알아야 한다.
2. 예외 처리의 정의와 목적
프로그램의 실행 도중에 발생하는 에러는 어쩔 수 없지만, 예외는 프로그래머가 이에 대한 처리를 미리 해주어야 한다.
예외처리란, 프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 것이며 예외처리의 목적은 예외의 발생으로 인한 실행 중인 프로그램의 갑작스런 비정상 종료를 막고, 정상적인 실행 상태를 유지할 수 있도록 하는 것이다.
정의: 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것.
목적: 프로그램의 비정상 종료를 막고, 정상적인 실행 상태를 유지하는 것.
3. try...catch...finally
try...catch는 예외에서 핵심적인 역할을 담당하는 문법적인 요소다. 형식을 살펴보자.
class Calculator{
int left, right;
public void setOprands(int left, int right){
this.left = left;
this.right = right;
}
public void divide(){
try {
System.out.print("계산결과는 ");
System.out.print(this.left/this.right);
System.out.print(" 입니다.");
} catch(Exception e){
System.out.println("\n\ne.getMessage()\n"+e.getMessage());
System.out.println("\n\ne.toString()\n"+e.toString());
System.out.println("\n\ne.printStackTrace()");
e.printStackTrace();
}
}
}
public class CalculatorDemo {
public static void main(String[] args) {
Calculator c1 = new Calculator();
c1.setOprands(10, 0);
c1.divide();
}
}
(1) try
try 안에는 예외 상황이 발생할 것으로 예상되는 로직을 위치시킨다. 예를 들어, 사용자가 setOprands의 두 번째 인자로 숫자 0을 입력했을 때 문제가 발생할 수 있음을 예측할 수 있다. 그래서 이 로직을 try 구문으로 감싼 것이다.
(2) catch
catch 안에는 예외가 발생했을 때 뒷수습을 하기 위한 로직이 위치한다.
(3) finally
class A{
private int[] arr = new int[3];
A(){
arr[0]=0;
arr[1]=10;
arr[2]=20;
}
public void z(int first, int second){
try {
System.out.println(arr[first] / arr[second]);
} catch(ArrayIndexOutOfBoundsException e){
System.out.println("ArrayIndexOutOfBoundsException");
} catch(ArithmeticException e){
System.out.println("ArithmeticException");
} catch(Exception e){
System.out.println("Exception");
} finally {
System.out.println("finally");
}
}
}
public class ExceptionDemo1 {
public static void main(String[] args) {
A a = new A();
a.z(10, 0);
a.z(1, 0);
a.z(2, 1);
}
}
실행결과)
ArrayIndexOutOfBoundsException
finally
ArithmeticException
finally
2
finally