스터디/CS

[CS] 자바 예외 - Java Exception

kwang2134 2025. 4. 7. 18:41
728x90
반응형
728x90

자바에서는 크게 Checked Exception과 Unchecked Exception으로 나뉩니다. Error는 예외와 별개로 시스템의 비정상적인 상황을 나타내어 Error에 대한 처리는 개발자가 직접 다루지 않습니다.

Checked Exception

자바에서 컴파일 시점에 체크되는 예외로 프로그램의 안정성과 신뢰성을 높이기 위해 사용됩니다. 주로 외부 요인에 의해 발생하는 예외를 다루기 위해 설계되어 파일 입출력, 네트워크 연결, 데이터베이스 쿼리 실행 등에서 발생할 수 있는 예외가 해당됩니다.

특징

  • 컴파일 시점 체크: 메서드 선언에서 throws 키워드를 사용하여 명시적으로 선언해야 함 → 컴파일러가 예외 처리 여부를 체크하고 처리하지 않는 경우 예외 발생
  • 명시적 처리: 체크드 예외는 반드시 try-catch 블록으로 감싸 처리하거나 메서드 선언에서 throws로 상위 계층에 전파해야 함 → 예외 발생 코드 명시적 관리 가능
  • 외부 요인에 의한 예외: 주로 외부 요인으로 인해 발생하는 예외를 다룸 → 파일이 존재하지 않거나 네트워크 연결에 실패하는 등
  • 예외 처리 강제: 예외 처리를 강제하여 개발자가 예외 상황을 무시하거나 처리하지 않는 경우 방지

처리 방법

try-catch 블록 사용

  • 예외 발생이 가능한 코드를 try블록으로 감싸고 예외 발생 시 처리를 catch 블록에 구현
try {
    // 예외 발생 가능 코드
    FileInputStream fis = new FileInputStream("example.txt");
} catch (IOException e) {
    // 예외 처리 코드
    System.out.println("파일을 읽을 수 없습니다.");
}

 

throws

  • 예외를 처리하지 않고 상위 계층으로 전파하여 해당 메서드를 사용하게 될 곳에서 처리하는 방법
  • 메서드를 호출한 곳으로 예외 전달
public void readFile() throws IOException {
    FileInputStream fis = new FileInputStream("example.txt");
    // ...
}

정리

  • 항상 컴파일 시점에 체크되어 개발자가 예외 상황을 미리 고려하고 처리 가능 → 안정성을 높임
  • 호출 계층 전체에서 예외를 선언하거나 예외 처리 코드가 추가되어 불필요한 코드가 생김

Unchecked Exception

런타임 시점에 발생하는 예외로 컴파일 시점에 체크 되지 않습니다. 주로 프로그래밍 논리 오류나 API 사용 실수 등으로 인해 발생하며 RuntimeException과 Error 클래스의 하위 클래스로 구성됩니다.

특징

  • 런타임 시점 발생: 프로그램 실행 중에 발생하며 컴파일러가 예외 처리 여부를 체크하지 않음
  • 프로그래밍 논리 오류: 주로 프로그래밍 논리 오류, API 사용 실수, 문법 오류 등으로 인해 발생
  • 명시적 처리 불필요: try-catch 블록을 통해 처리가 가능하긴 하지만 명시적으로 처리하지 않아도 컴파일 오류가 발생하지 않음

종류

  • ArithmeticException: 잘못된 산술 연산(예: 0으로 나누기) 시 발생
  • NullPointerException: null 참조 객체에 메서드를 호출할 때 발생
  • ArrayIndexOutOfBoundsException: 배열의 유효 범위를 벗어난 인덱스에 접근할 때 발생
  • NumberFormatException: 문자열을 숫자로 변환할 수 없을 때 발생
  • InputMismatchException: 잘못된 입력 형식으로 인해 발생
  • IllegalStateException: 객체의 상태가 메서드 호출에 적합하지 않을 때 발생

정리

  • 예외 처리가 강제 되지 않음 → 핵심 로직 코드만 남기 때문에 코드가 간결함
  • 예외 처리가 부족하여 의도치 않은 예외 발생 시 프로그램이 종료될 가능성이 있음 → 안정성이 떨어짐

자바에서 예외를 처리하는 방법

1. try-catch - 예외 복구

  • 정의: 예외 상황을 파악하고 문제를 해결하여 정상 흐름으로 변경하는 방법
  • 사용 방법: try 블록 내에 수행할 작업을 구현하고 catch 블록 내에 예외 발생 시 처리할 로직을 구현
//연결 실패 시 일정 횟수만큼 재시도를 통해 연결을 얻는 코드
final int MAX_RETRY = 100;

public Object someMethod() {
    int maxRetry = MAX_RETRY;
    while(maxRetry > 0) {
        try {
            // 예외 발생 가능 로직
            return; // 성공시 바로 리턴
        } catch(Exception e) {
            // 예외 발생시 로그를 출력
        } finally {
            // 리소스 반납 및 정리 작업
            --maxRetry; // 실패하면 재시도
        }
    }
    // 최대 재시도 횟수를 넘기면 직접 예외를 발생
    throw new RetryFailedException();
}

2. 처리 회피

  • 정의: 예외 처리를 직접 담당하지 않고 상위 계층으로 전파하여 호출한 곳에서 처리하는 방식
  • 사용 방법: 메서드 시그니처에 throws 키워드로 발생하는 예외를 선언
public void add() throws SQLException {
    try {
        // 예외 발생 가능 로직
    } catch(SQLException e) {
        e.printStackTrace(); // 로그만 출력하고
        throw e; // 다시 날린다
    }
}

// try-catch 없이도 메서드 시그니처에 발생하는 예외만 선언하면 됨
public void add() throws SQLException {
    // 예외 발생 가능 로직   
}

3. 예외 전환

  • 정의: 발생한 예외를 다른 예외로 변환하여 처리하는 방법
    • 더 명확한 의미를 가진 예외로 전환
    • Checked Exception을 UncheckedException으로 전환 → 예외 의존성을 줄이기 위함
  • 사용 방법: 전파 받은 예외를 다른 예외 클래스로 변경하여 전파
// 명확한 예외 전환
// 연동된 데이터베이스와의 작업에서 발생하는 SQLException을 더 명확한 내용으로 구분하기 위해 
try {
    // 데이터베이스 쿼리 실행 코드
} catch (SQLException e) {
    if (e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
        throw new DuplicateUserIdException(e); // SQLException을 DuplicateUserIdException으로 전환
    } else {
        throw new RuntimeException(e); // 다른 경우에는 일반적인 RuntimeException으로 전환
    }
}

// 예외 의존성을 줄이기 위한 전환
// 기존의 체크드 예외인 SQLException을 다른 계층으로 전파하게 되면 외부 요인인 
// 데이터베이스 예외에 의존하게 되므로 코드의 간결성을 위해 Unchecked Exception으로 전환
// SQLException을 그대로 다른 계층으로 전파하는 경우 
// 데이터베이스와 직접적인 연결이 없는 계층에서 데이터베이스 예외를 의존하는 경우 발생
public class DuplicateUserIdException extends RuntimeException {
    public DuplicateUserIdException() {
        super("사용자 ID가 이미 존재합니다.");
    }

    public DuplicateUserIdException(String message) {
        super(message);
    }

    public DuplicateUserIdException(Throwable cause) {
        super(cause);
    }

    public DuplicateUserIdException(String message, Throwable cause) {
        super(message, cause);
    }
}

728x90