프로그램을 실행하다 보면 어떤 원인 때문에 비정상적인 동작
을 일으키며 프로그램이 종료되는 상황이 발생한다.
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);
}
}
정말 보기 쉽게 정리해주셨네요! 감사합니다 :)