프로그램이 실행 중 어떤 원인에 의해 오작동을 하거나 비정상적으로 종료되는 경우가 있다. 이런 경우 흔히들 ‘에러 났다!’라고 표현하곤 하는데, 자바에서는 이렇게 프로그램 실행 시(runtime)에 발생할 수 있는 오류를 에러(Error)와 예외(Exception)로 구분하여 처리한다.
에러가 발생하면 프로그램 종료를 막기는 어렵지만, 예외는 발생하더라도 프로그래머가 이를 적절히 처리하도록 미리 코드상에서 처리를 해두어 비정상적인 문제를 방지할 수 있다.
- 에러(Error):
- 프로그램 코드로 수습할 수 없는 심각한 오류를 의미한다.
- JVM의 내부 문제나 시스템 수준의 오류 등으로 인해 발생하며, 프로그램이 정상적으로 복구되기 어렵다.
- 예:
StackOverflowError
,OutOfMemoryError
.
- 예외(Exception):
- 프로그램 코드로 예외적인 상황을 처리할 수 있는 오류를 의미한다.
- 예외가 발생하더라도 적절한 예외 처리 코드를 통해 프로그램의 비정상 종료를 방지할 수 있다.
이제 자바의 예외 처리와 관련된 Throwable
, Exception
클래스와 throw
, throws
키워드의 차이점을 살펴보자.
Throwable과 Exception
1. Throwable 클래스
자바의 예외 처리는 Throwable
클래스에서 시작된다. Throwable
은 모든 예외(Exception
)와 오류(Error
)의 최상위 클래스로, 예외와 오류 객체의 공통적인 특징을 정의한다.
java.lang.Object
└─ java.lang.Throwable
├─ java.lang.Exception // 예외 클래스
└─ java.lang.Error // 오류 클래스
- 자바에서 모든 오류와 예외의 최상위 클래스이다.
- JVM이 예외를 던지거나, 프로그래머가
throw
키워드를 사용하여 예외를 던질 때,Throwable
의 인스턴스 또는 그 하위 클래스만이 사용될 수 있다. catch
구문에서도Throwable
또는 그 하위 클래스만 예외 타입으로 받을 수 있다.
예외 발생 시 Throwable
의 주요 역할
- 스택 트레이스(Execution Stack) 정보 제공:
- printStackTrace(): 예외 발생 당시의 스택 추적 정보를 콘솔에 출력
Throwable
객체는 예외가 발생한 시점의 실행 스택 상태를 포함하며, 예외 발생 당시의 메서드 호출 순서를 기록한다.- 이를 통해 예외의 발생 지점을 추적하고 디버깅할 수 있다.
- 메시지 문자열:
- getMessage(): 예외나 오류에 대한 설명 메시지 반환
- 예외가 발생한 이유를 설명하는 추가적인 메시지를 포함할 수 있다.
- 원인(cause) 추적 및 예외 체인:
- getCause(): 예외의 근본 원인을 반환하여 예외 체인 추적
Throwable
객체는 다른 예외나 오류를 원인(cause)으로 포함할 수 있다.- 이를 통해 예외 체인(exception chaining)을 형성하여, 최초 예외 발생 원인부터 연속적인 예외 발생을 추적할 수 있다.
- 예외 체인을 사용하면, 다중 계층에서 발생한 예외를 하나의 흐름으로 관리하여, 구체적인 예외의 원인을 추적하기가 용이해진다.
2. Exception 클래스
Exception
클래스는 Throwable
의 자식 클래스로, 예외적인 상황을 처리하기 위한 클래스이다.
Throwable
클래스의 하위 클래스로, 회복 가능한 예외적인 상황을 나타낸다.- 대부분의 예외 처리(
try-catch
)는Exception
클래스와 그 하위 클래스에서 이루어진다.
Exception
의 두 가지 종류
- 체크드 예외 (Checked Exception):
- 컴파일 시점에 예외 처리를 강제하는 예외.
Exception
클래스를 상속하지만,RuntimeException
을 상속하지 않는 예외.- 예:
IOException
,SQLException
.
- 언체크드 예외 (Unchecked Exception):
RuntimeException
을 상속하는 예외로, 컴파일러가 예외 처리를 강제하지 않는다.- 주로 런타임 시점에 발생하며, 프로그램의 논리적 오류나 잘못된 접근을 나타낸다.
- 예:
NullPointerException
,IndexOutOfBoundsException
.
Throw와 Throws
1. Throw
키워드
- 예외를 직접 발생시킬 때 사용하는 키워드.
throw
키워드를 사용하여 예외 객체를 생성하고 던질 때 메서드의 실행이 즉시 종료되며, 발생한 예외는 상위 메서드로 전달된다.- 프로그래머가 의도적으로 특정 조건이 맞지 않을 때 예외를 발생시키기 위해 사용된다.
throw new 예외클래스("예외 메시지");
public class Main {
public static void main(String[] args) {
// try-catch 블록을 통한 예외 처리
try {
validateAge(15); // 유효하지 않은 나이로 인해 예외 발생
} catch (IllegalArgumentException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
// 특정 조건에 맞지 않을 때 예외를 던짐
public static void validateAge(int age) {
if (age < 18) {
// 예외 발생: 메서드 내에서 직접 예외 객체를 생성하여 던짐
throw new IllegalArgumentException("나이는 18세 이상이어야 합니다.");
}
// 예외가 발생할 경우 해당 라인에서 즉시 종료되어 아래 라인까지 도달하지 않음
System.out.println("나이가 유효합니다: " + age);
}
}
validateAge
메서드에서 특정 조건(나이 18세 미만) 일 때 의도적으로 예외를 발생시키고, 이를throw
키워드를 사용해 상위 호출 메서드로 전달한다.main
메서드에서는try-catch
블록을 통해 예외를 처리한다.
2. Throws
키워드
throws
는 메서드 선언부에서 사용되며, 해당 메서드가 특정 예외를 던질 수 있음을 명시한다.- 주로 체크드 예외가 발생할 수 있는 메서드에서 사용하며, 호출자는 예외 처리를 강제받는다.
반환타입 메서드명(매개변수 목록) throws 예외클래스1, 예외클래스2 .. {}
예외 처리를 강제받아 throws
키워드가 붙어있는 메서드는 반드시 try-catch 블록 내에서 호출되어 catch 블록에서 떠넘겨받은 예외를 처리해야 한다. (혹은 한번 더 throws로 호출한 곳으로 넘길 수도 있다)
public void method1() {
try {
method2();
} catch (ClassNotFoundException e) {
// 예외 처리 코드
System.out.println("예외 발생");
}
}
// 예외를 호출한 곳으로 한번 더 떠넘기는 것도 가능하다.
// public void method1() throws ClassNotFoundException {
// method2();
// }
public void method2() throws ClassNotFoundException {
Class clazz = Class.forname("java.lang.String2");
}
- method2 메서드는 throw ClassNotFoundException을 사용하여 체크드 예외를 호출자에게 전달한다.
- 호출자 method1 메서드는 method2를 호출할 때 try-catch 블록을 사용하여 예외를 처리하거나, mehotd1 메서드를 호출한 호출자에게 throws 키워드를 통해 한번 더 떠넘길 수도 있다.
Throw vs Throws 정리
특징 | throw | throws |
용도 | 예외를 직접 발생시킬 때 사용 | 메서드가 예외를 던질 수 있음을 선언 |
위치 | 메서드 내부 | 메서드 선언부 |
역할 | 예외 객체를 직접 던짐 | 해당 메서드가 어떤 예외를 던질 수 있는지 선언 |
예외 종류 | RuntimeException, CheckedException 모두 가능 | CheckedException의 강제 예외 처리 수단으로 사용, RuntimeException도 사용 가능 |
사용 개수 | 여러 개 throw 가능 | 메서드 선언부에 여러 예외 선언 가능 |
Reference
도서
- Java의 정석(남궁성 저)
- 이것이 자바다(신용권 저)
'Java > 일반' 카테고리의 다른 글
Annotation과 리플렉션이 뭘까? 어떤 관계일까? (0) | 2024.10.22 |
---|---|
Java의 람다(Lambda)와 스트림(Stream)이 뭘까? 왜 사용할까? (0) | 2024.10.08 |
Java의 final 키워드, 사용법과 객체 참조 시 주의점은? (0) | 2024.10.02 |
Java 추상 클래스(abstract class) vs 인터페이스(interface) 언제, 어떻게 사용할까? (0) | 2024.10.01 |
Java의 instanceof란? 마음껏 사용해도 될까? (0) | 2024.09.28 |
댓글