자바 사용자 정의 예외 만들기

요약

예외를 상속하는 클래스를 통해 예외를 만들 수 있다.
생성자를 통해 에러 메시지를 초기화 할 수 있다.

배경

1
2
3
4
5
public void checkCarNameEmpty(String carName) {
if (carName == null || carName.equals("")) {
throw new RuntimeException("자동차 이름이 입력되지 않았습니다!");
}
}

다음같이 작성하면 자동차 이름이 빈 문자열이거나 null인 경우 런타임예외를 발생시킨다.

RuntimeException은 너무 포괄적인 의미이니 도메인에 적합한 예외를 만들어보자.

예외 클래스 만들기

1. 생성자를 그대로 사용하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class EmptyCarNameException extends RuntimeExecption {

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

public EmptyCarNameException(Throwable cause) {
super(message);
}

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

이런 식으로 예외를 상속한 클래스를 만들고, 생성자들을 만들면 커스텀 예외로 활용할 수 있다.

2. 좀 더 활용하기

1
2
3
4
5
public class CarNameException extends RuntimeException {
public CarNameException(String message) {
super(message);
}
}

먼저 자동차 이름에 관련된 예외들이 모두 상속하는 수퍼클래스를 만들었다.

1
2
3
4
5
public class EmptyCarNameException extends CarNameException {
public EmptyCarNameException() {
super("빈 문자열을 자동차 이름으로 입력할 수 없습니다.");
}
}

자동차 이름 예외를 상속받도록 하였고,
이미 특정 도메인 상황을 예외로 만들고 싶어서 사용자 정의 예외를 만들었기 때문에, 굳이 매번 에러메시지를 입력받아 생성할 필요가 없다고 생각했다.
그래서 예외 클래스에 정해진 에러 메시지로 초기화하도록 만들었다.

실제 코드에 적용시켜보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class CarName {
private static int MAX_CAR_NAME_LENGTH = 5;
private static String EMPTY_STRING = "";

private final String carName;

public CarName(String carName) {
checkCarName(carName);
this.carName = carName;
}

private static void checkCarName(String input) {
checkCarNameNotNull(input);
checkCarNameLength(input);
checkCarNameExists(input);
checkCarNameIsNotSpace(input);
}

private static void checkCarNameNotNull(String carName) {
if (carName == null) {
throw new CarNameNullPointerException();
}
}

private static void checkCarNameLength(String carName) {
if (carName.length() > MAX_CAR_NAME_LENGTH) {
throw new CarNameLengthOverException(carName.length());
}
}

private static void checkCarNameExists(String carName) {
if (carName.equals(EMPTY_STRING)) {
throw new CarNameNotExistsException();
}
}

private static void checkCarNameIsNotSpace(String carName) {
if (carName.trim().equals(EMPTY_STRING)) {
throw new CarNameSpaceException();
}
}
}

이제 도메인에서 우리가 만든 사용자 예외를 검증해보자.
도메인 객체가 만들어지기 전에 예외를 모두 검증한다.

테스트해보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CarNameTest {

private static Stream<Arguments> provideCarNameAndExceptionMessage() {
return Stream.of(
Arguments.of(null, "자동차 이름을 찾을 수 없습니다!"),
Arguments.of("다섯글자이상", "자동차 이름은 5자 이하여야 합니다."),
Arguments.of("", "모든 자동차 이름은 반드시 존재해야 합니다."),
Arguments.of(" ", "자동차 이름은 공백으로 설정할 수 없습니다."),
Arguments.of(" ", "자동차 이름은 공백으로 설정할 수 없습니다.")
);
}

@ParameterizedTest
@MethodSource(value = "provideCarNameAndExceptionMessage")
public void 자동차_이릅_예외_테스트(String carName, String message) {
assertThatThrownBy(() -> new CarName(carName))
.isInstanceOf(CarNameException.class)
.hasMessageContaining(message);
}
}

다양한 예외 상황마다 예외 객체와 예외 메시지를 통해 테스트를 할 수 있다!

사용자 예외의 장단점

장점

  1. 클래스의 이름으로 어떤 예외인지 가늠가능하다.

    CarNameEmtpyException이면 어떤 상황인지 바로 이해가능하다!

  2. 상세한 예외 정보를 제공할 수 있다.

    자동차의 이름 길이가 5를 넘기면 예외를 발생시키고자 한다. 이때 사용자가 입력한 이름의 길이도 함께 알려주고 싶다면?

    1
    2
    3
    4
    5
    public class CarNameLengthOverException extends CarNameException {
    public CarNameLengthOverException(int length) {
    super("자동차 이름은 5자 이하여야 합니다. 입력된 글자 수 : " + length);
    }
    }
  3. 예외 핸들링이 용이하다.

  4. 해당 예외 상황에 관련된 정보를 한 곳에 관리 가능하다.

단점

  1. 새로운 클래스를 작성해줘야 된다.

    굳이 이미 있는 예외 클래스로도 처리 가능한데, 굳이 새로운 클래스를 작성해야 될 지 고민해야한다.

Share