1. Enum 타입을 이용한 연산자 타입 정보 관리
🤔 enum이란?
- 미리 정의된 특별한 집합
- 대문자로 적는것을 원칙으로 함
1차 시도 코드
//CalculatorApp.java
// 연산자 체크
OperatorType operatorType = OperatorType.valueOf(operatorInput);
//OperatorType.java
// 연산자 구분
public enum OperatorType {
PLUS("+"),
MINUS("-"),
MULTIPLY("*"),
DIVIDE("/");
private final String type;
OperatorType(String type) {
this.type = type;
}
public String getType() {
return type;
}
결과
No enum constant example.calculator3.OperatorType.+
위와 같은 오류가 나타났다.
번역해보면 열거형 상수 없음이다. 왜 이런 결과가 나타날까?
처음 생각했을 때는 + 를 입력하면 OperatorType의 값과 동일한 PLUS가 출력될 것이라 예상했다
그러나 valueOf가 지칭하는것이 PLUS 이다.
따라서 값인 '+'를 입력했을때 name값 PLUS를 호출할 수 있는 별도의 메서드가 필요했다!
해결방안
// 연산 기호를 입력받아 type 매핑을 위한 메서드 추가!
public static OperatorType changeType(String type){
// values : OperatorType의 모든 값(+, -, *, %)
for(OperatorType operatorType : values()){
if(operatorType.getType().equals(type)){
return operatorType;
}
}
throw new RuntimeException(new Exception().getMessage());
}
-> 스트림으로 변환
public static OperatorType changeType(String type) throws Exception {
// values() = 배열
return Arrays.stream(OperatorType.values())
.filter(operator -> operator.getType().equals(type))
.findAny()
.orElseThrow(() -> new ErrorException(ErrorCode.WRONG_OPERATOR));
}
// 연산자 체크
OperatorType operator = OperatorType.changeType(operatorInput);
2. 제네릭을 이용하여 실수(double) 타입의 값을 받아도 연산이 가능하도록 수정
// ArithmeticCalculator.java
// 해당 클래스에서 매개변수 T를 숫자형타입(Integer, Double 등으로 제한)
public class ArithmeticCalculator <T extends Number> {
}
CalculatorApp.java
// 사칙연산 진행 및 저장
calculator.setList(calculator.result(
calculator.getNum1(), calculator.getNum2(), operator)
);
// ArithmeticCalculator.java
// 저장
public void setList(T result) {
list.add(result);
}
// 사칙 연산시 제네릭 타입의 경우 연산 불가
// double형으로 변환 뒤 연산
double result(T num1, T num2, OperatorType operator){
double result = 0;
switch (operator){
case PLUS:
result = num1.doubleValue() + num2.doubleValue();
break;
case MINUS:
result = num1.doubleValue() - num2.doubleValue();
break;
case MULTIPLY:
result = num1.doubleValue() * num2.doubleValue();
break;
case DIVIDE:
result = num1.doubleValue() / num2.doubleValue();
break;
}
return result;
3. 저장된 연산 결과들 중 Scanner로 입력받은 값보다 큰 결과값 들을 출력
1차 시도 코드
public List<T> getChkList(){
return list
.stream()
.filter(i -> i > getList())
.mapToDouble(Double::parseDouble)
.toList();
}
결과 오류 발생
operator '>' cannot be applied to 't', 't'
🤔 오류 발생원인은?
- T는 Number를 상속 받았더라도 추상적인 형태를 지님
- 숫자타입이 아닌 T의 경우 연산자(+,-,*,/,>,>= ....)를 사용하기 위해선 기본타입 int, double 등으로 변경 필요!
- mapToDouble(Double::parseDouble) : String -> double형태로 변환하는 것이기 때문에 오류 발생
해결방안
public List<T> getChkList(){
return list
.stream()
.filter(i -> i.doubleValue() > getList().doubleValue())
.toList();
}
4. 예외 처리 추가하기
public enum ErrorCode {
WRONG_TYPE("입력된 값이 숫자가 아닙니다."),
WRONG_DIVISION("나눗셈 연산시 분모(두번째 숫자)는 0을 입력할 수 없습니다."),
WRONG_OPERATOR("연산자는 +, -, *, / 중 하나를 입력해야합니다.");
private final String error;
ErrorCode(String error) {
this.error = error;
}
public String getError() {
return error;
}
}
public class ErrorException extends Exception{
public ErrorException(ErrorCode errorCode) {
super(errorCode.getError());
}
}
// ArithmeticCalculator.java
// 정규표현식을 이용하여 실수체크
private static final String NUMBER_REG = "^-?[0-9]+(\\.[0-9]+)?$";
// 입력된 값 숫자 여부 체크
public double parseNum(String num) throws Exception{
if (!Pattern.matches(NUMBER_REG, String.valueOf(num))) {
throw new ErrorException(ErrorCode.WRONG_TYPE);
}
return Double.parseDouble(num);
}
// 나눗셈 분모 체크
public void chkDivide(String operatorIntput) throws Exception{
if ((getNum2().doubleValue() == 0) && operatorIntput.equals("/")) {
throw new ErrorException(ErrorCode.WRONG_DIVISION);
}
}
// OperatorType.java
// 연산 타입(+, -, *, /)가 아닌 경우 오류 생성
public static OperatorType changeType(String type) throws Exception {
// values : OperatorType의 모든 값(+, -, *, /)
return Arrays.stream(OperatorType.values())
.filter(operator -> operator.getType().equals(type))
.findAny()
.orElseThrow(() -> new ErrorException(ErrorCode.WRONG_OPERATOR));
}