Octoping의 블로그

우테코 3주차 미션 [로또]를 하다가 마주한 요구사항이었다.

 

사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`를 발생시키고, 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.

 

 

예제와 함께 구현해보기

간단한 예제를 들어보자.

다음과 같은 함수들을 만들어야 한다고 하자.

  • 0 이상의 양수를 입력받는 getTryCount()
  • 1과 45 사이의 숫자를 중복 없이 6개 받고, 보너스 번호도 받는 getLottoNumber()
  • 그 외 등등 다른 input 함수들

 

간단히 만들어보기

getTryCount 만들어보기

일단 올바른 값이 들어올 때까지 무한해서 입력을 다시 받아야하니, while + if - break의 조합으로 만들어야 할 것이다.

그리고 잘못된 값이 발생하면 에외를 발생시켜야하므로 while문 안에 try-catch 문이 필요할 것이다.

 

public int getTryCount() {
    while(true) {
        try {
            String input = scanner.nextLine();

            validateIsNumber(input);
            validateIsPositive(input);

            return Integer.parseInt(input);
        } catch(IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }
}

코드가 이렇게 되겠다.

일단 아무 것도 안했는데 들여쓰기 중첩이 2개인게 벌써부터 화난다..

 

일단 다음 함수를 만들러 가자.

 

getLottoNumber 만들어보기

public LottoNumber getLottoNumber() {
    List<Integer> lottoNumber;
    while (true) {
        try {
            String input = scanner.nextLine();

            validateIsNumber(input);
            validateIsInRange(input);
            validateIsDuplicate(input);

            lottoNumber = mapToIntegerList(input);
        } catch(IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }

    int bonusNumber;
    while (true) {
        try {
            String input = scanner.nextLine();

            validateIsNumber(input);
            validateIsInRange(input);
            validateIsDuplicateWithLottoNumber(input, lottoNumber);

            bonusNumber = Integer.parseInt(input);
        } catch(IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }

    return new LottoNumber(lottoNumber, bonusNumber);
}

로또 숫자를 받고, 보너스 번호도 받아야 한다.

덕분에 while-try-catch가 2개나 들어왔다.

 

 

문제점

이와 같은 방식은 문제가 크게 2개 있다.

 

첫번째로, 입력을 받는 메소드들의 개수만큼 이 while - try - catch문이 계속 중복이 된다. 

두 번째로는 이 while문 때문에 실제 로직에 시선이 집중되지 않고 복잡하니 시선이 분산된다.

 

이 while-try-catch 문의 코드 중복을 처리하고 싶다는 욕망이 강하게 든다.

그런데, 이 구문의 안에 있는 '함수'는 어떻게 해야 추출할 수 있을까?

 

 

while-try-catch문 추출해서 중복 제거하기

우리는 while-try-catch문을 이용해서, 제대로 된 값을 얻을 수 있을 때까지 무한 루프를 돌도록 구현했다.

즉, while-try-catch문 안에 있는 함수는 '값을 제공하는 함수'이다.

 

그러므로 이 안의 함수를 Supplier를 통해 치환할 수 있을 것같다.

 

private <T> T doLoop(Supplier<T> inputFunction) {
    while (true) {
        try {
            return inputFunction.get();
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }
}

파라미터로 온 값이 예외를 발생하지 않을 때까지 무한 루프를 돌다가 값을 반환하는 함수를 만들어냈다.

 

 

getTryCount 다시 만들기

우리가 만든 doLoop을 이용해서 코드를 다시 만들어보자.

 

public int getTryCount() {
    return doLoop(() -> {
        String input = scanner.nextLine();

        validateIsNumber(input);
        validateIsPositive(input);

        return Integer.parseInt(input);
    });
}

확실히 좀 깔끔해진 것 같다.

기존에는 while-try-catch라는 매서운 녀석들 때문에 로직에 온전히 집중이 되지 않고 시선이 분산되었는데, 이제는 딱 로직에 집중할 수있게 되었다.

 

 

getLottoNumber 다시 만들기

얘도 다시 만들어보자.

public LottoNumber getLottoNumber() {
    List<Integer> lottoNumber = doLoop(() -> {
        String input = scanner.nextLine();

        validateIsNumber(input);
        validateIsInRange(input);
        validateIsDuplicate(input);

        return mapToIntegerList(input);
    });
    
    int bonusNumber = doLoop(() -> {
        String input = scanner.nextLine();

        validateIsNumber(input);
        validateIsInRange(input);
        validateIsDuplicateWithLottoNumber(input, lottoNumber);

        return Integer.parseInt(input);
    });

    return new LottoNumber(lottoNumber, bonusNumber);
}

 

좋다.

'언어 > Java' 카테고리의 다른 글

record에서 배열 사용하지 않기  (0) 2023.08.28
클래스 내의 모든 변수 이름, 값 가져오기  (0) 2022.06.18
언박싱 메소드  (0) 2022.06.18
Divided by Zero 에러 double 형  (0) 2022.06.18
profile

Octoping의 블로그

@Octoping

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!