본문 바로가기
Java

[JAVA] 사용자 정의 예외 만들기

by teamnova 2025. 4. 24.
728x90

안녕하세요.

오늘은 사용자 정의 예외를 만들어보겠습니다.

 

1. Checked 예외와 Unchecked 예외의 차이와 특징

(1) Checked 예외 (체크드 예외)

  • 컴파일러가 예외 처리를 강제합니다.
  • 예외가 발생할 수 있는 코드를 사용할 때, 반드시 try-catch로 처리하거나 throws로 선언해야 합니다.
  • 주로 외부 환경(파일 입출력, 네트워크, 데이터베이스 등)과 관련된 예외입니다.
  • 예시: IOException, SQLException
try {
    FileReader fr = new FileReader("test.txt");
} catch (FileNotFoundException e) {
    System.out.println("파일이 없습니다!");
}

 

(2) Unchecked 예외 (언체크드 예외)

  • 컴파일러가 예외 처리를 강제하지 않습니다.
  • 예외가 발생할 수 있는데도, 꼭 try-catch로 감싸지 않아도 됩니다.
  • 주로 프로그래밍 실수(코딩 오류, 논리 오류)에서 발생합니다.
  • 예시: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException
String text = null;
System.out.println(text.length()); // NullPointerException 발생 (컴파일러가 강제하지 않음)

 

2. 사용자 정의 예외 만들기

내가 원하는 예외 상황이 있을 때, 예외 클래스를 직접 만들어 사용할 수 있습니다.
이때, Checked 예외Unchecked 예외 둘 다 만들 수 있습니다.

(1) Checked 예외 직접 만들기

  • Exception 클래스를 상속해서 만듭니다.
  • 예외를 던지는 메서드는 반드시 throws로 선언하거나, try-catch로 처리해야 합니다.

예제: 나이가 0보다 작으면 예외 발생

// 사용자 정의 Checked 예외
public class NegativeAgeException extends Exception {
    public NegativeAgeException(String message) {
        super(message);
    }
}

// 사용하는 코드
public class CheckedCustomExceptionTest {
    public static void checkAge(int age) throws NegativeAgeException {
        if (age < 0) {
            throw new NegativeAgeException("나이는 0보다 작을 수 없습니다.");
        }
        System.out.println("나이: " + age);
    }

    public static void main(String[] args) {
        try {
            checkAge(-5); // 예외 발생
        } catch (NegativeAgeException e) {
            System.out.println("예외 발생: " + e.getMessage());
        }
    }
}

 

(2) Unchecked 예외 직접 만들기

  • RuntimeException 클래스를 상속해서 만듭니다.
  • 예외를 던지는 메서드에 throws를 선언하지 않아도 되고, 예외 처리를 강제하지 않습니다.

예제: 점수가 0~100 범위를 벗어나면 예외 발생

// 사용자 정의 Unchecked 예외
public class InvalidScoreException extends RuntimeException {
    public InvalidScoreException(String message) {
        super(message);
    }
}

// 사용하는 코드
public class UncheckedCustomExceptionTest {
    public static void checkScore(int score) {
        if (score < 0 || score > 100) {
            throw new InvalidScoreException("점수는 0~100 사이여야 합니다.");
        }
        System.out.println("점수: " + score);
    }

    public static void main(String[] args) {
        checkScore(150); // 예외 발생, 컴파일러가 강제하지 않음
        System.out.println("프로그램 종료");
    }
}

 

3. 실전 예제: 회원가입/로그인 시스템에서의 예외 처리

실제 프로젝트에서 자주 사용하는 회원가입/로그인 시스템을 예로 들어,
Checked/Unchecked 예외와 사용자 정의 예외를 어떻게 활용할 수 있는지 살펴봅니다.

(1) 예외 상황 설계

  • Checked 예외
    • 데이터베이스(DB) 연결 실패, 파일 입출력 실패 등 외부 리소스 문제
  • Unchecked 예외
    • 아이디/비밀번호가 null이거나 형식이 잘못된 경우, 중복 아이디 등 비즈니스 로직 위반

(2) 사용자 정의 예외 클래스 만들기

// Checked 예외: DB 연결 실패
public class DatabaseConnectionException extends Exception {
    public DatabaseConnectionException(String message) {
        super(message);
    }
}

// Unchecked 예외: 아이디 중복
public class DuplicateUsernameException extends RuntimeException {
    public DuplicateUsernameException(String message) {
        super(message);
    }
}

// Unchecked 예외: 비밀번호 형식 오류
public class InvalidPasswordFormatException extends RuntimeException {
    public InvalidPasswordFormatException(String message) {
        super(message);
    }
}

 

(3) 회원가입 로직에 예외 적용하기

import java.util.HashSet;
import java.util.Set;

public class UserService {
    private Set<String> usernames = new HashSet<>();

    // DB 연결 시도 (예시)
    private void connectToDatabase() throws DatabaseConnectionException {
        // 실제로는 DB 연결 코드가 들어감
        boolean dbConnected = false; // 일부러 실패로 가정
        if (!dbConnected) {
            throw new DatabaseConnectionException("데이터베이스 연결에 실패했습니다.");
        }
    }

    // 회원가입 메서드
    public void register(String username, String password) throws DatabaseConnectionException {
        connectToDatabase(); // Checked 예외 발생 가능

        if (username == null || username.isEmpty()) {
            throw new IllegalArgumentException("아이디를 입력하세요.");
        }
        if (usernames.contains(username)) {
            throw new DuplicateUsernameException("이미 존재하는 아이디입니다.");
        }
        if (password == null || password.length() < 6) {
            throw new InvalidPasswordFormatException("비밀번호는 6자 이상이어야 합니다.");
        }

        usernames.add(username);
        System.out.println("회원가입 성공: " + username);
    }

    public static void main(String[] args) {
        UserService userService = new UserService();

        try {
            userService.register("hong", "123456");
        } catch (DatabaseConnectionException e) {
            System.out.println("DB 오류: " + e.getMessage());
        } catch (DuplicateUsernameException e) {
            System.out.println("중복 아이디: " + e.getMessage());
        } catch (InvalidPasswordFormatException e) {
            System.out.println("비밀번호 오류: " + e.getMessage());
        } catch (Exception e) {
            System.out.println("알 수 없는 오류: " + e.getMessage());
        }
    }
}

 

실행 결과 예시

DB 오류: 데이터베이스 연결에 실패했습니다.

만약 dbConnected를 true로 바꾸고 이미 존재하는 아이디로 가입을 시도하면
"중복 아이디: 이미 존재하는 아이디입니다."
가 출력됩니다.