우테코 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 |