JAVA (15) - 예외 처리
1. 개요
프로그램 실행 중에는 구문 오류(Syntax Error) 외에도 예측하지 못한 상황으로 인해 오류가 발생할 수 있다. 자바에서는 이러한 비정상 종료를 막고 프로그램이 정상적인 흐름을 유지할 수 있도록 예외 처리(Exception Handling) 메커니즘을 제공한다.
2. 에러(Error)와 예외(Exception)
자바에서는 실행 시점(Runtime)에 발생할 수 있는 오류를 크게 에러와 예외로 구분한다.
- 에러 (Error): 메모리 부족(
OutOfMemoryError)이나 스택 오버플로우(StackOverflowError)와 같이 시스템 수준에서 발생하는 심각한 문제다. 복구가 불가능하며 프로그램이 종료된다. - 예외 (Exception): 프로그램 코드에 의해 수습될 수 있는 비교적 미약한 오류다. 개발자가 적절한 코드를 작성하여 비정상 종료를 방지할 수 있다.
1
2
3
4
java.lang.Throwable
├── java.lang.Error
└── java.lang.Exception
3. Checked Exception vs Unchecked Exception
Exception 클래스의 하위 예외는 크게 두 가지 유형으로 나뉜다.
(1) Checked Exception (체크 예외)
RuntimeException을 상속받지 않은 예외 클래스다. (예:IOException,SQLException)- 컴파일 시점에 예외 처리 여부를 검사한다.
- 예외 처리가 강제되므로
try-catch로 잡거나throws로 던져야 컴파일이 가능하다.
(2) Unchecked Exception (언체크 예외 / 실행 예외)
RuntimeException을 상속받는 예외 클래스다. (예:NullPointerException,IndexOutOfBoundsException,IllegalArgumentException)- 컴파일 시점에 예외 처리를 검사하지 않는다.
- 주로 개발자의 실수나 잘못된 로직으로 인해 발생하며, 예외 처리를 명시적으로 강제하지 않는다.
4. try - catch - finally 구문
예외를 직접 처리할 때 사용하는 가장 기본적인 구조다.
1
2
3
4
5
6
7
8
9
10
11
try {
// 예외가 발생할 가능성이 있는 코드
int result = 10 / 0;
} catch (ArithmeticException e) {
// 해당 예외가 발생했을 때 처리할 코드
System.out.println("0으로 나눌 수 없다: " + e.getMessage());
} finally {
// 예외 발생 여부와 상관없이 항상 실행되는 코드 (생략 가능)
// 주로 자원 해제(Resource close) 등에 사용
}
- Multi-catch: 자바 7부터는 하나의
catch블록에서|기호를 사용하여 여러 예외를 동시에 잡을 수 있다.
5. try-with-resources
파일, DB 연결, 네트워크 소켓 등 자원(Resource)을 사용한 후 반납해야 할 때, 기존에는 finally 블록에서 일일이 .close()를 호출해야 했다. 자바 7에서 도입된 try-with-resources 구문을 사용하면 자원을 자동으로 해제해 준다.
try 뒤에 괄호 ()를 붙여 자원을 선언해 주는 특수한 구문을 사용해야 자동으로 처리
AutoCloseable인터페이스를 구현한 클래스만 적용 가능하다.
1
2
3
4
5
6
7
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line = br.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
} // try 블록을 벗어나면 br.close()가 자동으로 호출됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("file.txt"));
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 사용이 끝나면 무조건 실행되는 finally에서 직접 close()를 호출해야 함
if (br != null) {
try {
br.close(); // close() 할 때도 예외 처리가 필요하여 코드가 매우 지저분해짐
} catch (IOException e) {
e.printStackTrace();
}
}
}
6. 예외 던지기 (throws) 및 커스텀 예외
메서드 내부에서 예외를 직접 처리하지 않고, 자신을 호출한 상위 메서드로 예외 처리를 위임할 수 있다.
1
2
3
4
public void readFile(String filePath) throws IOException {
FileReader fr = new FileReader(filePath); // 예외를 직접 처리하지 않고 상위로 던짐
}
비즈니스 로직에 맞춘 도메인 전용 예외가 필요하다면 RuntimeException을 상속받아 사용자 정의 예외(Custom Exception)를 만들어 활용할 수 있다.
1
2
3
4
5
6
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
7. 정리
자바의 예외 처리는 프로그램의 비정상 종료를 예방하고 안정성을 높이는 핵심 기법이다. 컴파일 시점에 체크되는 Checked Exception과 명시적 처리를 강제하지 않는 Unchecked Exception의 차이를 구분하여 사용해야 한다. 자원 해제가 필요한 경우에는 try-with-resources 구문을 활용하여 코드를 간결하고 안전하게 유지하는 것이 바람직하다.