🖥️ try, catch, finally
public class ExceptionHandlingExample {
public static void main(String[] args) {
try {
int result = divide(10, 0);
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("예외 발생: " + e.getMessage());
} finally {
System.out.println("프로그램 종료");
}
}
public static int divide(int a, int b) throws ArithmeticException {
if (b == 0) {
throw new ArithmeticException("0으로 나눌 수 없습니다.");
}
return a / b;
}
}
위 코드에서 divide 메서드는 두 수를 나누는 기능을 한다. 만약 두 번째 인자가 0이라면 ArithmeticException을 발생시키고, 이를 main 메서드에서 try-catch 블록으로 처리한다. finally 블록은 예외 발생 여부와 상관없이 항상 실행되어 "프로그램 종료"를 출력한다.
🖥️ throw
throw: 프로그래머가 의도적으로 예외를 발생시킬 때 사용
public class ThrowExample {
public static void checkAge(int age) {
if (age < 18) {
throw new IllegalArgumentException("나이가 18세 이상이어야 합니다.");
}
System.out.println("성인입니다.");
}
public static void main(String[] args) {
checkAge(15); // 예외 발생
}
}
checkAge(15);를 호출하면 IllegalArgumentException이 발생한다.
🖥️ throws
메서드 선언부에 사용되어 해당 메서드가 특정 예외를 던질 수 있음을 명시
public class ThrowsExample {
public static void riskyMethod() throws Exception {
throw new Exception("예외 발생!");
}
public static void main(String[] args) {
try {
riskyMethod();
} catch (Exception e) {
System.out.println("예외 처리: " + e.getMessage());
}
}
}
riskyMethod는 throws Exception을 선언하여 예외를 호출한 곳에서 처리하도록 한다. main 메서드에서는 try-catch로 예외를 처리한다.
🖥️ try-with-resources
Java 7에서 들어온 기능으로 AutoCloseable 인터페이스를 구현한 클래스에서 자동으로 자원을 해제하도록 도와준다. 대표적으로 BufferedReader, FileReader, InputStream 등이 해당된다.
// Java 7 이후 try-with-resources
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
// Java 7 이전
static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
try 블록이 종료되면 BufferedReader가 자동으로 닫힌다. 기존의 finally 블록 대신에 resource(java.lang.AutoClosable 이나 java.io.Closable을 구현한 오브젝트)를 자동으로 반환하여close()가 자동으로 호출된다.
자바의 예외 계층 구조는 java.lang.Throwable 클래스를 최상위 클래스로 하며, 이는 두 가지 주요 하위 클래스를 가진다 : Exception / Error

Throwable 클래스란?
오류와 예외 모두 자바의 최상위 클래스인 Object를 상속받는다. 그리고 그 사이에는 Throwable 클래스와 상속관계가 있는데, Throwable 클래스의 역할은 오류나 예외에 대한 메시지를 담는 것이다.
대표적으로getMessage()와printStackTrace()메서드가 바로 이 클래스에 속해 있다. 당연히 Throwable을 상속받은 Error와 Exception 클래스에서도 위 두 메서드를 사용할 수 있게 된다.
위의 예외 클래스 계층 구조를 더 간단히 표현하면 아래와 같다.
자바에서 다루는 모든 예외 오류는 Exception 클래스에서 처리한다. 그리고 아래의 Exception 클래스 트리 구조를 보면 파랑색과 붉은색으로 색깔별로 구분됨을 볼 수 있는데, 이것이 컴파일 에러와 런타임 에러를 따로 클래스로 구분했기 때문이다.
시스템 레벨에서 발생하는 심각한 오류로, 주로 JVM의 문제나 하드웨어 한계로 인해 발생한다. 개발자가 이를 처리하여 복구하기 어렵기 때문에 애플리케이션에서 처리하지 않는 것이 일반적이다.
ex) OutOfMemoryError, StackOverflowError
프로그램에서 발생할 수 있는 예외 상황을 나타내며, 개발자가 이를 처리하여 프로그램의 정상적인 흐름을 유지할 수 있다. 아래와 같이 두가지로 나뉜다.
IOException, SQLException, FileNotFoundException 등NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException, SystemException 등위에서 다룬 내용이며, 요약하자면 아래와 같다.
| 구분 | RuntimeException (Unchecked Exception) | Checked Exception |
|---|---|---|
| 컴파일 시 검사 여부 | ❌ 컴파일러가 예외 처리를 강제하지 않음 | ✅ 컴파일러가 예외 처리를 강제함 |
| 예외 처리 필요 여부 | 예외 처리를 강제하지 않아 try-catch 없이도 컴파일 가능 | 반드시 try-catch 또는 throws를 사용해야 함 |
| 발생 시점 | 실행(Runtime) 중에 주로 발생 | 컴파일 타임에 예외 가능성을 체크함 |
| 원인 | 주로 프로그래머의 실수로 발생 (예: NullPointerException) | 외부 환경(파일, 네트워크, DB 등)과 관련된 예외 |
| 처리 방식 | 프로그램 실행 중 예외 발생 시 종료될 수도 있음 | 반드시 예외 처리를 통해 정상적인 흐름을 유지해야 함 |
| 예제 코드 | public void divide(int a, int b) { int result = a / b; } (0으로 나누면 ArithmeticException 발생) | public void readFile() throws IOException { FileReader file = new FileReader("test.txt"); } |
자바에서는 사용자 정의 예외를 만들어 특정 상황에 대한 예외 처리를 세분화할 수 있다. 이를 위해 Exception 클래스를 상속하여 새로운 예외 클래스를 정의한다.
// 사용자 정의 예외 클래스
public class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
// 예외를 사용하는 클래스
public class CustomExceptionExample {
public static void main(String::contentReference[oaicite:0]{index=0}