예외(Exception)와 예외 처리(try-catch)

하마·2025년 2월 26일

Java

목록 보기
2/8

예외란?


  • 프로그램 실행 중 예상하지 못한 상황이 발생하는 것을 의미
    • 대표적인 산술 예외: 10 / 0
  • 의도적으로 예외를 발생시킬 때throw 키워드를 통해 발생시킵니다.
  • 예외를 처리하지 않으면 프로그램이 중단되기 때문에
    try-catch 를 통해 안정적으로 프로그램의 실행을 보장합니다.

예외 발생 예제


1️⃣ 의도하지 않은 예외

public class Main {
    public static void main(String[] args) {
        System.out.println("프로그램 시작");
        // ❌ 예외 발생 (ArithmeticException)
        int result = 10 / 0;
        System.out.println("이 문장은 실행되지 않음");
    }
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at chapter3.exception.Main.main(Main.java:8)

Process finished with exit code 1

2️⃣ 의도적인 예외 - throw

public class Main {
    public static void main(String[] args) {
        int age = 10;
        if (age < 18) {
		    // ✅ 의도적으로 예외를 발생시키는 부분
            throw new IllegalArgumentException("미성년자는 접근할 수 없습니다!");
        }
        System.out.println("....");
    }
}

예외 구조와 종류


  • RuntimeException - Unchecked
    • RuntimeException 을 상속받는 모든 예외를 UncheckedException 라 함
    • 예외를 컴파일러가 확인하지 않음 → Unchecked
    • 예상치 못했던 상황에서 발생하는 것이 아니므로
      굳이 예외 처리를 강제하지 않음
    • 개발자가 실수로 예외 처리를 누락할 수 있는 단점이 있음
  • Exception - Checked
    • Exception 을 상속받는 모든 예외를 CheckedException 라 함
      RuntimeExceptionRuntimeException 을 상속받은 예외는 제외
    • 예외를 컴파일러가 확인해 줌 → Checked
    • 개발자가 실수로 예외 처리를 누락하지 않도록 도와주기 때문에
      예외 처리를 강제함
    • 모든 체크 예외를 처리해줘야 하기 때문에 번거롭고,
      신경쓰지 않고 싶은 예외까지 처리해야 하는 단점이 있음

실무에서 발생하는 예외들은 복구 불가능한 경우가 많다.
예를 들어 SQLExceptoin과 같은 체크 예외를 catch해도, 쿼리를 수정하여 재배포하지 않는 이상 복구되지 않는다.
그래서 실제 개발에서는 대부분 언체크 예외를 사용한다.


예외 전파


  • 예외가 발생했을 때 해당 메소드에서 처리되지 않았을 경우
    메소드를 호출한 상위 메소드로 예외를 전달
  • 예외는 main() 까지 올라가고, 처리되지 않으면 프로그램이 비정상 종료됨

1️⃣ RuntimeException

  • 컴파일러가 예외 처리를 강제하지 않는 예외
  • 예외 처리를 하지 않아도 컴파일 오류가 발생하지 않음
public class ExceptionPractice {
    public void callUncheckedException() {
        if (true) {
            System.out.println("언체크 예외 발생");
            throw new RuntimeException(); // ✅ 예외발생 
        }
    }
}

throw 를 통해 상위 메소드(여기서는 main())로 예외를 떠넘김

public class Main {
    public static void main(String[] args) {
        ExceptionPractice exceptionPractice = new ExceptionPractice();

        // ✅ 언체크 예외 호출
        exceptionPractice.callUncheckedException();
        
        // ❌ 예외처리를 해주지 않았기 때문에 프로그램이 종료됩니다.
        System.out.println("이 줄은 실행되지 않습니다."); 
    }
}

예외 처리를 하지 않았기 때문에 오류가 발생합니다.
main() 에서 예외 처리를 해줍시다.

public class Main {
    public static void main(String[] args) {
        ExceptionPractice exceptionPractice = new ExceptionPractice();
        
        // ✅ 상위로 전파된 예외처리
        try {
            exceptionPractice.callUncheckedException();

        } catch (RuntimeException e) { // ✅ 예외처리
            System.out.println("언체크 예외 처리");   
            
        } catch (Exception e) {
            System.out.println("체크 예외 처리");
        }

        System.out.println("프로그램 종료");
    }
}

catch() 는 여러 개가 될 수 있습니다.
발생한 예외에 따라 서로 다른 예외 처리를 해줄 수 있습니다.

2️⃣ Exception

  • 컴파일러가 예외 처리를 강제하는 예외
  • 예외 처리를 하지 않으면 컴파일 오류가 발생함
public class ExceptionPractice {
    public void callCheckedException() {
		// ✅ try-catch 로 예외 처리
        try { 
            if (true) {
                System.out.println("체크예외 발생");
                throw new Exception();
            }
        } catch (Exception e) {
            System.out.println("예외 처리");
        }
    }
}
public class Main {
    public static void main(String[] args) {
        ExceptionPractice exceptionPractice = new ExceptionPractice();

        // ✅ 체크예외 호출
        exceptionPractice.callCheckedException();
    }
}

RuntimeException과 동일한 방법(try-catch)으로
예외 처리를 합니다.

📌 예외를 호출한 곳에서 처리하도록 강제하는 방식 (책임전가)

메소드에 throws 키워드를 사용해서 상위 메소드에서 예외를 처리하도록 합니다.

public class ExceptionPractice {
    // ✅ throws 예외를 상위로 전파
    public void callCheckedException() throws Exception {
        if (true) {
            System.out.println("체크예외 발생");
            throw new Exception();
        }
    }
}
public class Main {
    public static void main(String[] args) {
        ExceptionPractice exceptionPractice = new ExceptionPractice();

        // 체크 예외 사용
        // ✅ 반드시 상위 메서드에서 try-catch 를 활용해 주어야합니다.
        try {
            exceptionPractice.callCheckedException();
        } catch (Exception e) {
            System.out.println("예외처리");
        }
    }
}

📌 throwthrows 를 헷갈리지 않도록 사용합니다.

키워드사용 위치예시
throw메소드 내부throw new Exception();
throws메소드 이름 옆public void callException() throws Exception {}

정리


  • 예외가 처리되지 않으면 프로그램이 비정상적으로 종료될 수 있기 때문에
    예외 처리는 필수입니다.
  • CheckedException 은 컴파일러를 통해 반드시 처리해야 하는 예외를 알려줍니다.
  • UncheckedException 은 개발자가 충분히 예측하고 방지할 수 있는 경우 사용합니다.
    → 숫자를 0으로 나누는 오류 등은 코드 검토로 충분히 예방 가능합니다.
    → 이런 예외 처리까지 CheckedException 으로 처리하도록 강제한다면 모든 예외 상황을 처리해야 하는 답답한 상황이 벌어져 개발 생산성이 저하되고 불필요한 코드가 많아질 수 있습니다.

참고자료

https://mangkyu.tistory.com/152
챕터 3-1: 예외(Exception)과 예외처리(try-catch)

0개의 댓글