[Java] 예외 처리에서 반복되는 try-catch 추출하기

신재우·2023년 12월 21일
1

우테코 6기 프리코스 활동 중...

입력 시 예외가 발생하면 에러 메시지 출력 후 재입력해야 했다.

입력을 여러 번 받으니 동일한 구조의 while-try-catch 문도 여러 개였다.

개발자는 반복된 작업을 싫어하는 법.

함수형 인터페이스에 대해 알아야 이해할 수 있다.

당첨 번호를 입력해 주세요.
1,2,3,4,5,100

[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.

당첨 번호를 입력해 주세요.

Before

public class LottoController {

	private final InputView inputView;
    
    // 생성자, 비즈니스 로직 생략
    
    private LottoPurchaseMoney askPurchaseMoney() {
    	while (true) {
	    	try {
	        	int money = inputView.askPurchaseMoney();
	            return new LottoPurchaseMoney(money);
	        } catch (IllegalArgumentException exception) {
        		System.out.printf("[Error] " + exception.getMessage());
        	}        
        }
    }
    
    private Lotto askWinningNumbers() {
    	while (true) {
			try {
	    		List<Integer> lottoNumbers = inputView.askWinningNumbers();
                return new Lotto(lottoNumbers);
		    } catch (IllegalArgumentException exception) {
		    	System.out.printf("[ERROR] " + exception.getMessage());
		    }
        }
    }
    
    private LottoWinningNumbers createWinningNumbers(Lotto lottoNumbers) {
    	while (true) {
			try {
				int bonusNumber = inputView.askBonusNumber();
				return new LottoWinningNumbers(lottoNumbers, bonusnumber);
			} catch (IllegalArgumentException exception) {
				System.out.printf("[ERROR] " + exception.getMessage());
			}
		}
    }
}

After

public class ExceptionHandler {

    private static final String ERROR = "[ERROR] ";

    public <T> T run(Supplier<T> callback) {
        while (true) {
            try {
                return callback.get();
            } catch (IllegalArgumentException exception) {
                System.out.println(ERROR + exception.getMessage());
            }
        }
    }
}

public class LottoController {

	private final InputView inputView;
    private final ExceptionHanlder exceptionHanlder;
    
    // 생성자, 비즈니스 로직 생략
    
    private LottoPurchaseMoney askPurchaseMoney() {
    	return exceptionHandler.run(() -> {
        	int money = inputView.askPurchaseMoney();
            return new LottoPurcahseMoney(money);
        });
    }
    
    private Lotto askWinningNumbers() {
    	return exceptionHandler.run(() -> {
        	List<Integer> lottoNumbers = inputView.askWinningNumbers();
            return new Lotto(winningNumbers);
        });
    }
    
    private LottoWinningNumbers createWinningNumbers(Lotto lottoNumbers) {
    	return exceptionHandler.run(() -> {
        	int bonusNumber = inputView.askBonusNumber();
            return new LottoWinningNumbers(lottoNumbers, bonusNumber);
        });
    }
}

반환값이 없는 경우

null을 반환하는 메서드를 작성하면 된다.

public class ExceptionHandler {

    private static final String ERROR = "[ERROR] ";

    public <T> void runWithNoReturnValue(Supplier<T> callback) {
        run(() -> {
            callback.get();
            return null;
        }, message);
    }

    public <T> T run(Supplier<T> callback) {
        while (true) {
            try {
                return callback.get();
            } catch (IllegalArgumentException exception) {
                System.out.println(ERROR + exception.getMessage());
            }
        }
    }
}

관련 주제

자바 함수형 인터페이스

자바 java.util.function 공식 문서

본 블로그에서는 함수형 인터페이스 중 Supplier를 사용했으나, 필요에 따라 다른 인터페이스로 응용할 수 있다.

자바 제네릭(Generics)

자바 제네릭 튜토리얼 공식 문서

ExceptionHandlerSupplierrun 메서드는 어떤 타입이든 반환할 수 있도록 제네릭 문법을 사용하고 있다.

전략 패턴

Refactoring Guru 전략 패턴

공통 로직이 있고, 일부 행동만 바뀐다는 점에서 전략 패턴을 적용했다고 할 수 있다.

0개의 댓글