본문 바로가기

개발일지/TIL

[ 230615 ] Java 계산기 메서드 작성하기

만든 이유

강의를 듣고 간단하게 계산기 만드는 과제가 있었다. " 피연산자 (연산자) 피연산자" 형식의 값을 입력받아 계산을 해주었다. 그러다 보니 연속된 연산을 거치기 위해서는 입력을 여러 번 해야 했다. 긴 계산식을 한 번에 받아 처리해 주는 메서드를 작성해 보기로 했다.

 

[ 입력 형식 변경 ]

"피연산자 (연산자) 피연산자" -> "피연산자 (연산자) 피연선자 (연산자) 피연산자 ..."

Java 코드 작성

숫자, 연산자를 저장하는 Stack 객체를 2개 만들었다. 맨 마지막에 있는 값을 결과로 사용하고 싶어서 FILO형태의 자료구조를 선택한 것이다. 그리고 기본 분기는 operator 중심으로 작성해서 처리했다. 문자를 다룰 때는 변동이 많은 경우 StringBuilder를 사용해 처리했다. String은 값을 할당할 때마다 새로운 객체가 만들어지기 때문이다.

 

public double calculate(String[] expression) {
    Stack<Double> numbers = new Stack<>();
    Stack<String> operators = new Stack<>();

    StringBuilder number = new StringBuilder();
    for(String element : expression) {
         
        // 요소가 연산자인 경우 이전 연산자를 확인
        if(isOperator(element)) {
            String preOperator = operators.empty() ? null : operators.pop();

            // 이전 연산자가 없는 경우 숫자를 숫자 Stack에 넣음
            if(preOperator == null) {
                numbers.push(Double.valueOf(number.toString().trim()));
            }
            // [연산자 우선순위] 이전 연산자가 곱셈, 나눗셈인 경우 연산을 한 후 결과 값을 숫자 Stack에 넣음
            else if (preOperator.equals("*") || preOperator.equals("/")){
                setOperator(preOperator);
                numbers.push(abstractOperation.operate(numbers.pop(), 
                             Double.valueOf(number.toString().trim())));
            } 
            // 그 이외에는 이전 연산자를 연산자 Stack, 숫자를 숫자 Stack에 넣음
            else {
                operators.push(preOperator);
                numbers.push(Double.valueOf(number.toString().trim()));
            }

            // 다음 숫자를 읽어오기 위해 StringBuilder 초기화
            number.delete(0, number.length());
            // 현재 연산자를 연산자 Stack에 넣음
            operators.push(element);
        } else {
            number.append(element);
        }
    }

    // 표현식이 다 끝나고 마지막 숫자를 숫자 Stack에 넣어줌
    if(number.length() != 0 && !number.toString().equals("=")){
        numbers.push(Double.valueOf(number.toString().trim()));
    }

    // 연산자 +, -를 연산자 Stack과 숫자 Stack을 사용해 계산
    while(!operators.empty()){
        Double operand_one = numbers.pop();
        Double operand_two = numbers.pop();
        setOperator(operators.pop());
        Double result = abstractOperation.operate(operand_two, operand_one);
        numbers.push(result);
    }

    return numbers.pop();
}

문제가 될 수 있는 것

괄호 "(", ")" 가 적용되지 않았다. 숫자와 연산자 이외에 값이 섞여있을 경우에 대한 처리가 되어있지 않다. 이런 표현식이 들어온다면 문제가 될 수가 있다. 그래서 일단 정규식을 적용하여 정해놓은 형식만 받도록 했다. 

 

[ 정규식 적용 ]

expression.matches("[0-9\s\\+\\-\\*\\/]+")

결과