프로그램을 실행하다 보면 어떤 원인 때문에 비정상적인 동작을 일으키며 프로그램이 종료되는 상황이 발생한다.
Checked Exception과 Unchecked Exception으로 분류한다.
컴파일 시점에 확인되는 예외
예외적인 상황을 안전하게 관리하고, 안정성을 높이기 위해 사용하는데, 체크 예외는 Exception 클래스를 상속하지만, RuntimeException을 상속받지 않는 모든 예외가 여기에 속한다.
명시적으로 처리해야 하며, 이를 위해 try-catch 블록을 사용하거나 throws 키워드를 메서드 선언에 추가하여 예외를 던질 수 있다.
런타임 시점에 확인되는 예외
프로그램의 오류나 잘못된 로직으로 인해 발생한다. RuntimeException 클래스를 상속받아 정의된다.
NullPointerException, IndexOutOfBoundsException, IllegalArgumentException 등명시적인 처리를 강제하지 않으며, 대부분의 경우 프로그램의 오류를 수정함으로써 해결된다.
프로그램의 실행 과정에서 호출된 메서드들의 순서와 위치 정보를 나타내는 것
일반적으로 예외가 발생했을 때 예외가 발생한 지점부터 호출 스택의 상위 메서드들까지의 정보를 담고 있다.
try-catch 구문을 사용한 경우, printStackTrace() 메서드를 호출하여 출력할 수 있다.try-catch 구문을 사용하지 않은 경우, 스택 트레이스 정보가 자동으로 출력되지만 오류 발생 지점과 호출 경로를 파악하기 어려워 디버깅과 오류 분석에 제한이 생긴다.public class ExceptionHandlingRunner {
public static void main(String[] args) {
method1(); // 코드 라인 6
}
private static void method1() {
String str = null;
str.length(); // 코드 라인 수 11
}
}
실행 결과
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is null
at udemy.ExceptionHandlingRunner.method1(ExceptionHandlingRunner.java:11)
at udemy.ExceptionHandlingRunner.main(ExceptionHandlingRunner.java:6)
NullPointerException이라는 런타임 에러가 발생되어 스택 트레이스(Stack Trace)가 출력된 것을 확인할 수 있다.public class ExceptionHandlingRunner2 {
public static void main(String[] args) {
method1(); // 코드 라인 6
System.out.println("Main Ended");
}
private static void method1() {
method2(); // 코드 라인 11
System.out.println("Method1 Ended");
}
// try & catch 문으로 method1로 예외를 떠넘기기 방지
private static void method2() {
try {
String str = null;
str.length(); // 코드 라인 19
System.out.println("Method2 Ended");
} catch (NullPointerException ex) {
System.out.println("Matched NullPointerException");
ex.printStackTrace();
} catch (Exception ex) {
System.out.println("Matched Exception");
ex.printStackTrace();
}
}
}
실행 결과
Matched NullPointerException
Method1 Ended
Main Ended
java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is null
at udemy.ExceptionHandlingRunner2.method2(ExceptionHandlingRunner2.java:19)
at udemy.ExceptionHandlingRunner2.method1(ExceptionHandlingRunner2.java:11)
at udemy.ExceptionHandlingRunner2.main(ExceptionHandlingRunner2.java:6)
public class FinallyRunner {
public static void main(String[] args) {
Scanner sc = null;
try {
sc = new Scanner(System.in);
int[] numbers = {12, 3, 4, 5};
int number = numbers[5]; // 코드 라인 12
} catch (ArrayIndexOutOfBoundsException ex) {
ex.printStackTrace();
} finally {
System.out.println("Before Scanner Close");
if (sc != null) {
sc.close();
}
}
System.out.println("Just before closing out main");
}
}
실행 결과
java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 4
at udemy.FinallyRunner.main(FinallyRunner.java:12)
Before Scanner Close
Just before closing out main
if(sc ≠ null)을 통해 자원을 해제하면 된다.public class TryWithResourceRunner {
public static void main(String[] args) {
try (Scanner sc = new Scanner(System.in)) {
int[] numbers = {12, 3, 4, 5};
int number = numbers[21];
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
throws 키워드를 명시적으로 선언함으로써 메서드를 사용하는 측에서 해당 예외 처리를 위임할 수 있다.UncheckedException의 경우 throws를 선언하지 않아도 된다.class Amount {
private String currency;
private int amount;
public Amount(String currency, int amount) {
this.currency = currency;
this.amount = amount;
}
public void add(Amount that) throws Exception {
if(!this.currency.equals(that.currency)) {
throw new Exception("Currencies Don't Match " + this.currency + " & " + that.currency);
}
this.amount = this.amount + that.amount;
}
@Override
public String toString() {
return "Amount{" +
"currency='" + currency + '\'' +
", amount=" + amount +
'}';
}
}
public class ThrowingExceptionRunner {
public static void main(String[] args) throws Exception {
Amount amount1 = new Amount("USD", 10);
Amount amount2 = new Amount("EUR", 20);
amount1.add(amount2);
System.out.println(amount1);
}
}
출력 결과
Exception in thread "main" java.lang.Exception: Currencies Don't Match USD & EUR
at udemy.Amount.add(ThrowingExceptionRunner.java:14)
at udemy.ThrowingExceptionRunner.main(ThrowingExceptionRunner.java:42)
main 메서드의 선택지는 try & catch로 예외를 처리하거나, throws 키워드를 통해 예외를 던지는 방법이 있다.throws 키워드를 통해 예외 처리를 위임했다.class Amount {
private String currency;
private int amount;
public Amount(String currency, int amount) {
this.currency = currency;
this.amount = amount;
}
public void add(Amount that) throws CurrenciesDoNotMatchException {
if (!this.currency.equals(that.currency)) {
throw new CurrenciesDoNotMatchException("Currencies Don't Match " + this.currency + " & " + that.currency);
}
this.amount = this.amount + that.amount;
}
@Override
public String toString() {
return "Amount{" +
"currency='" + currency + '\'' +
", amount=" + amount +
'}';
}
}
// 사용자 정의 예외
class CurrenciesDoNotMatchException extends Exception {
public CurrenciesDoNotMatchException(String msg) {
super(msg);
}
}
public class ThrowingExceptionRunner {
public static void main(String[] args) throws CurrenciesDoNotMatchException {
Amount amount1 = new Amount("USD", 10);
Amount amount2 = new Amount("EUR", 20);
amount1.add(amount2);
System.out.println(amount1);
}
}
정말 보기 쉽게 정리해주셨네요! 감사합니다 :)