1. 프로그램 오류
프로그램이 실행 중 어떤 원인에 의해서 오작동 하거나 비정상적으로 종료되는 경우, 결과를 초래하는 원인을 프로그램 에러 또는 오류라고 한다.
- 컴파일 에러: 컴파일 시에 발생하는 에러
- 런타임 에러: 실행 시에 발생하는 에러
- 논리적 에러: 실행은 되지만, 의도와 다르게 동작하는 것(ex. 개수가 음수가 나올 때)
컴파일이 성공적으로 마쳤다고 해서 프로그램의 실행 시에도 에러가 발생하지 않은 것은 아니다. 프로그램이 실행 중 동작을 멈추거나, 종료되는 경우처럼 런타임 에러가 발생할 수 있다.
런타임 에러를 방지하기 위해서는 프로그램 실행도중 발생할 수 있는 경우의 수를 고려하여 대비를 하는 것이 필요하고, 자바에서는 실행 시(runtime) 발생할 수 있는 프로그램 오류를 '에러(error)'와 '예외(exception)'으로 구분한다.
- 에러(error): 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
ex: 메모리 부족(OutOfMemoryError), 스택오버플로우(StackOverflowError) - 에외(exception): 프로그램 코드에 의해서 수습될 수 있는 다소 미양한 오류
2. 예외 클래스의 계층 구조
출처: TCP 스쿨
모든 클래스의 조상은 Object 클래스이므로 Exception과 Error 클래스도 Object 클래스의 자손이다.
예외 클래스는 두 그룹으로 나눌 수 있다.
- Exception 클래스와 그 자손들
- RuntimeException 클래스와 그 자손들
- Exception 클래스
외부의 영향으로 발생할 수 있는 것들로 프로그램의 사용자들의 동작에 의해서 발생하는 경우가 많다.FileNotFoundException
: 존재하지 않는 파일의 이름을 입력한 경우ClassNotFoundException
: 실수로 클래스의 이름을 잘못 적은 경우DataFormatException
: 입력한 데이터 형식이 잘못된 경우
- RuntimeException 클래스
프로그래머의 실수에 의해서 발생될 수 있는 예외들을 말한다.ArrayIndexOutOfBoundsException
: 배열의 범위를 벗어난 경우NullPointerException
: 값이 null인 참조변수의 멤버를 호출하는 경우ClassCastException
: 클래스간의 형변환을 잘못한 경우ArithmeticException
: 정수를 0으로 나누는 경우
3. 예외처리하기: try-catch문
예외처리란?
- 정의: 프로그램 실행 시 발생할 수 있는 예외에 대비한 코드를 작성하는 것
- 목적: 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것
발생한 예외를 처리하지 못하면, 프로그램은 비정상적으로 종료된다. 처리되지 못한 예외(uncaught exception)는 JVM의 '예외처리기(UncaughtExceptionHandler)'가 받아서 예외의 원인을 화면에 출력한다.
try-catch 문 구조
try{
예외가 발생할 가능성이 있는 문장
} catch (Exception1 e1){
// Exception1이 발생했을 경우, 처리하기 위한 문장 작성
} catch (Exception2 e1){
// Exception2가 발생했을 경우, 처리하기 위한 문장 작성
}
4. try-catch문의 흐름
try-catch문에서, 예외가 발생한 경우와 발생하지 않았을 때의 흐름(문장의 실행순서)이 달라진다.
try 블럭 내에서 예외가 발생한 경우
- 발생한 예외와 일치하는 catch 블럭이 있는지 확인한다.
- 일치하는 catch 블럭을 찾으면, 블럭 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 일치하는 catch 블럭을 찾지 못하면, 예외는 처리되지 못한다.
try 블럭 내에서 예외가 발생하지 않은 경우
- catch 블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다.
class Exception{
public static void main(String args[]){
System.out.println(1);
System.out.println(2);
try{
System.out.println(3);
System.out.println(0/0); // 0으로 나눠서 고의로 ArithmeticException을 발생시킨다.
System.out.println(4); // 실행되지 않는다.
} catch(ArithmeticException ae){
System.out.println(5);
} // try-catch 끝!
System.out.println(6);
} // main 메서드 끝!
}
/*
실행 결과
1
2
3
5
6
*/
5. 예외의 발생과 catch블럭
예외가 발생하면, 발생한 예외에 해당하는 클래스의 인스턴스가 생성된다.
class Exception{
public static void main(String args[]){
System.out.println(1);
System.out.println(2);
try{
System.out.println(3);
System.out.println(0/0); // 0으로 나눠서 ArithmeticException 발생
System.out.println(4); // 실행되지 않음
}catch(ArithmeticException ae){
if(ae instanceof ArithmeticException){
System.out.println("true")
System.out.println("ArithmeticException");
}catch(Exception e){ // ArithmeticException을 제외한 모든 예외가 처리됨
System.out.println("Exceptin");
} // try-catch의 끝
System.out.println(6);
} // main 메서드의 끝
}
/*
실행 결과
1
2
3
true
ArithmeticException
6
*/
첫 번째 검사에서 일치하는 catch 블럭을 찾았기 때문에 두 번째 catch 블럭은 검사하지 않는다. 만일 ArithmeticException이 아닌 다른 종류의 예러가 발생했다면 두 번째 catch 블럭에서 처리되었을 것이다.
printStackTrace()와 getMessage()
예외가 발생했을 때 생성되는 예외 클래스와 인스턴스에는 예외에 대한 정보가 담겨있고, 위 명령어를 통해 정보들을 얻을 수 있다.
- printStackTrace(): 예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.
- getMessage(): 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.
멀티 catch 블럭
여러 catch 블럭을 |
기호를 이용해서, 하나의 catch 블럭으로 합칠 수 있다.
여러 catch 블럭을 사용하는 경우
중복된 코드가 발생한다.
try{
...
} catch(ExceptionA e1){
e1.printStackTrace();
} catch(ExceptionB e2){
e2.printStackTrace();
}
멀티 catch 블럭
중복된 코드를 줄일 수 있다.
try{
...
} catch (ExceptionA | ExceptionB e){
e.printStackTrace();
}
만일 멀티 catch 블럭의 |
기호로 연결된 예외 클래스가 조상과 자손의 관계에 있다면 컴파일 에러가 발생한다. 조상 클래스가 자손 클래스를 포함하기 때문에 불필요한 코드는 제거하라는 의미이다. 다음과 같이 부모 클래스만 써주면 된다.
try{
...
}catch(ParentException e){
e.printStackTrace();
}
멀티 catch는 하나의 catch블럭으로 여러 예외를 처리하므로, 발생한 예외를 멀티 catch 블럭으로 처리했을 때 실제로 어떤 예외가 발생한 것인지 알 수 없다. 따라서 예외 클래스들의 공통 분모인 조상 예외 클래스에 선언된 멤버만 사용할 수 있다. 필요하다면 instanceof
로 어떤 예외가 발생한 것인지 확인하고 처리할 수 있다.
try{
...
}catch(ExceptionA | ExceptionB e){
e.methodA(); // 에러. ExceptionA에 선언된 methodA() 호출 불가
if(e instanceof ExceptionA){
ExceptionA e1 = (ExceptionA)e;
e1.methodA(); // OK. ExceptionA에 선언된 메서드 호출 가능
}else{ // if(e instanceof ExceptionB)
...
}
e.printStackTrace();
}
6. 예외 발생시키기
throw
키워드를 사용해서 프로그래머가 고의로 예외를 발생시킬 수 있다.
- 키워드
new
를 이용해서 발생시키려는 예외 클래스의 겍채를 만든다.Exception e = new Exception("고의로 발생시켰음");
- 키워드
throw
를 이용해서 예외를 발생시킨다.throw e;
Reference