계산기 LV3_generic, enum 오류해결

지혜·2025년 1월 7일

계산기 LV3

💡 https://github.com/cjh0412/calculator

조건

  • Enum 타입을 이용한 연산자 타입 정보 관리
  • 제네릭을 이용하여 실수(double) 타입의 값을 받아도 연산이 가능하도록 수정
    = [x] 저장된 연산 결과들 중 Scanner로 입력받은 값보다 큰 결과값 들을 출력
  • 예외 처리 추가하기

코드

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;
    }
}
  • exception 예외 생성
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));
    }

0개의 댓글