계산기 과제를 진행하던 중, 생각하게 된 주제이다.
level1: 클래스 없이 계산기 구현
level2: 클래스를 활용한 계산기 구현 - Calculator 클래스 분리
<참고>
'내일배움캠프(Spring 7기)/CH 2 계산기 과제' 카테고리의 글 목록
gajicoding 님의 블로그 입니다.
gajicoding.tistory.com
두 상황의 차이점을 잘 비교해보자
Level 1을 구현 후 피드백 받은 코드이다.
피드백 전
- switch 문 내부에서 예외 발생
- 실행 전 상태로 충분히 판단 가능한 예외를 굳이 실행에 맡김 (늦은 판단)
try {
// Scanner로 num1, num2, symbol을 입력받은 후
result = switch (symbol) {
case '+' -> num1 + num2;
case '-' -> num1 - num2;
case '*' -> num1 * num2;
case '/' -> num1 / num2;
default -> throw new Exception("사칙연산(+, -, *, /) 기호를 입력해야 한다.");
};
System.out.println("계산 결과: " + result);
} catch(ArithmeticException e) {
System.out.println("잘못된 입력: " + "0으로 나눌 수 없다." + "\n");
} (Exception e) {
System.out.println("잘못된 입력: " + e.getMessage() + "\n");
}
피드백 후
- switch 전에 예외 발생 가능 조건이 이미 존재 → 미리 체크하는 것이 더 좋음
- 예외를 예측 가능하면 먼저 던져라 !!!
try {
// Scanner로 num1, num2, symbol을 입력받은 후
if(num2 == 0 && symbol == '/') {
throw new ArithmeticException("0으로 나눌 수 없다.");
}
result = switch (symbol) {
case '+' -> num1 + num2;
case '-' -> num1 - num2;
case '*' -> num1 * num2;
case '/' -> num1 / num2;
default -> throw new Exception("사칙연산(+, -, *, /) 기호를 입력해야 한다.");
};
System.out.println("계산 결과: " + result);
} catch (Exception e) {
System.out.println("잘못된 입력: " + e.getMessage() + "\n");
}
Level 2 (클래스 분리)를 구현 후 피드백 받은 코드이다.
피드백 전
- 유효성 검사 후 calculate() 메서드 실행
// App 클래스
if(nums[1] == 0 && symbol == '/') {
System.out.println("잘못된 입력: " + "0으로 나눌 수 없다." + "\n");
continue;
}
res = calculator.calculate(nums[0], nums[1], symbol);
// Calulator 클래스의 calculate 메서드
public ... calculate(int num1, int num2, char symbol) {
int res;
try {
res = switch (symbol) {
case '+' -> num1 + num2;
case '-' -> num1 - num2;
case '*' -> num1 * num2;
case '/' -> num1 / num2;
default -> throw new Exception("사칙연산(+, -, *, /) 기호를 입력해야 한다.");
};
...
} catch(Exception e) {
System.out.println("잘못된 입력: " + e.getMessage() + "\n");
}
...
}
피드백 후
- 계산 책임은 Calculator에 있으므로, 예외도 내부에서 발생시켜야 한다.
- App은 여러 계산기 중 하나일 뿐 → "이 계산기가 어떤 예외를 던질 수 있는지"만 알고 있으면 된다.
- 역할 분리 원칙: 책임 있는 쪽에서 검증과 예외 발생까지 담당해야 재사용성이 높아진다.
// Main 클래스
res = calculator.calculate(nums, symbol);
// Calulator 클래스의 calculate 메서드
public ... calculate(int num1, int num2, char symbol) {
int res;
if(nums[1] == 0 && symbol == '/'){
throw new ArithmeticException("0으로 나눌 수 없다.");
}
try {
res = switch (symbol) {
case '+' -> num1 + num2;
case '-' -> num1 - num2;
case '*' -> num1 * num2;
case '/' -> num1 / num2;
default -> throw new Exception("사칙연산(+, -, *, /) 기호를 입력해야 한다.");
};
...
} catch(Exception e) {
System.out.println("잘못된 입력: " + e.getMessage() + "\n");
}
...
}
정리
- 입력값에 대한 검증은 입력을 받는 곳에서 한다
- 사용자 입력, 외부 데이터 등은 가능한 빨리 유효성 체크
- 로직 실행 중 발생할 수 있는 예외는 해당 로직 내부에서 처리하거나 던진다
- ex: 계산, 변환, 파일 처리 등
- 공통적인 검증이 필요할 경우, 유틸리티 클래스에 분리한다
- 여러 곳에서 재사용 가능하도록
'코드 개선 (refactoring) > Java' 카테고리의 다른 글
getItems.add(...) vs addItem(...) (0) | 2025.04.21 |
---|---|
Optional 제대로 사용하기 (1) | 2025.04.19 |