본문 바로가기

JAVA

다형성을 이용한 계산기 만들기 - 예외처리 추가

import java.util.Scanner;

public class CalculatorApp {

    public static boolean start() throws Exception { //throws Exception : 위험하다는 표시, 이에 대한 메서드의 예외 처리를 해줘야 함
        Parser parser = new Parser();
        Scanner scanner = new Scanner(System.in);

        System.out.println("첫번째 숫자를 입력해주세요!");
        String firstInput = scanner.nextLine();
        parser.parseFirstNum(firstInput);

        System.out.println("연산자를 입력해주세요!");
        String operator = scanner.nextLine();
        parser.parseOperator(operator);

        System.out.println("두번째 숫자를 입력해주세요!");
        String secondInput = scanner.nextLine();
        parser.parseSecondNum(secondInput);

        System.out.println("연산 결과 : " + parser.executeCalculator());
        return true;
    }


}
package org.tesk;

import java.util.regex.Pattern;

public class Parser {
    private static final String OPERATION_REG = "[+\\-*/]";
    private static final String NUMBER_REG = "^[0-9]*$";

    private final Calculator calculator = new Calculator();

    public Parser parseFirstNum(String firstInput) throws BadInputException{
        if (!Pattern.matches(NUMBER_REG, firstInput)) {
            throw new BadInputException("정수값");
        }

        this.calculator.setFirstNumber(Integer.parseInt(firstInput));
        return this;
    }

    public Parser parseSecondNum(String secondInput) throws BadInputException {
        if (!Pattern.matches(NUMBER_REG, secondInput)){
            throw new BadInputException("정수값");
        }

        this.calculator.setSecondNumber(Integer.parseInt(secondInput));
        return this;
    }

    public Parser parseOperator(String operationInput) throws BadInputException{
        if (!Pattern.matches(OPERATION_REG, operationInput)){
            throw new BadInputException("사칙연산 연산자");
        }

        switch (operationInput) {
            case "+" -> this.calculator.setOperation(new AddOperation());
            case "-" -> this.calculator.setOperation(new SubstractOperation());
            case "*" -> this.calculator.setOperation(new MultiplyOperation());
            case "/" -> this.calculator.setOperation(new DivideOperation());
        }

        return this;
    }

    public double executeCalculator() {
        return calculator.calculate();
    }
}
package org.tesk;

public class BadInputException extends Exception {
    public BadInputException(String type) {
        super("잘못된 입력입니다! " + type + "을 입력해주세요!");
    }
}
package org.tesk;

public class Calculator{

    private int firstNumber;
    private int secondNumber;

    private AbstractOperation operation;

    public Calculator(AbstractOperation operation){
        this.operation = operation;
    }

    public Calculator() {
    }

    public void setOperation(AbstractOperation operation) {
        this.operation = operation;
    }

    public void setFirstNumber(int firstNumber) {
        this.firstNumber = firstNumber;
    }

    public void setSecondNumber(int secondNumber) {
        this.secondNumber = secondNumber;
    }

    public double calculate() {
        double answer = 0;
        answer = operation.operate(this.firstNumber, this.secondNumber);
        return answer;
    }

}

 

package org.tesk;

public class Main {
    public static void main(String[] args) {
        boolean calculateEnded = false;

        try{
            calculateEnded = CalculatorApp.start();
        } catch (BadInputException e) {
            System.out.println(e.getMessage());
        }

    }
}

 

과제를 스스로 해결하기 어려웠던 점

  • public Parser parseFirstNum 메서드 부분에서 리턴을 어떻게 해줘야 할지 몰랐음
    • 그냥 this로 리턴을 해주면 됨
  • 이어서 리턴을 할 때 왜 굳이 저 메서드에서 Parser객체를 리턴해 줘야 하는지 고민을 했었다. return을 객체로 안해주면 오류가 안잡히나 생각을 해봤는데, void로 변경하고 실행해도 오류는 잘 잡혔다(당연히) 그냥 큰 이유없이 넣으신 것 같다는 결론이 나왔다

  • CalculatorApp 클래스의 존재에 대해서 망각하고 있어서 도대체 parser객체로만 어떻게 해야하나 생각한 것 같다
  • throws에 대한 개념이 약간 모호해서 이를 어떻게 연관된 클래스끼리 연결시켜서 던져야 되는지 어려웠던 것 같다

 

예외처리의 구조

  • throw : 예외 객체를 생성하고, 발생된 예외는 가장 가까운 try-catch 블록에서 처리
  • throws : 메서드 선언부에서 예외를 선언하면, 호출하는 쪽에서 해당 예외를 처리해야 함
public void checkDivision(int divisor) throws ArithmeticException {
    if (divisor == 0) {
        throw new ArithmeticException("Divisor cannot be zero.");
    }
    System.out.println(100 / divisor);
}

public static void main(String[] args) {
    try {
        checkDivision(0); // 0으로 나누기 시도
    } catch (ArithmeticException e) {
        System.out.println("Caught exception: " + e.getMessage());
    }
}

 

throw를 통해 ArithmeticException이라는 예외객체를 발생시키고 가장 가까운 try catch블록에서 처리하려고 했으나 throws 가 메서드에 선언되어 있기 때문에 이 메서드를 호출한 곳으로 에러처리를 위임 -> 그래서 main 메서드의 try-catch에서 에러를 잡아서 처리 

 

과제에서의 구조

  • 메서드 옆에 throws BadInputException 이 명시되어 있기 때문에 이를 호출한 메서드로 BadInputException을 위임
    public void parseFirstNum(String firstInput) throws BadInputException{
        if (!Pattern.matches(NUMBER_REG, firstInput)) {
            throw new BadInputException("정수값");
        }

        this.calculator.setFirstNumber(Integer.parseInt(firstInput));
//        return this;
    }

 

  • 이를 호출한 start()도 throws가 되어있으므로 또 위임
public class CalculatorApp {
    public static boolean start() throws BadInputException{
        Parser parser = new Parser();
        Scanner scanner = new Scanner(System.in);

        System.out.println("첫번째 숫자를 입력해주세요!");
        String firstInput = scanner.nextLine();
        parser.parseFirstNum(firstInput);

 

  • start()를 호출한 mian에서 catch로 에러 잡음
public class Main {
    public static void main(String[] args) {
        boolean calculateEnded = false;

        while (!calculateEnded) {
            try {
                calculateEnded = CalculatorApp.start();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

 

-> 그냥 throw는 에러객체를 생성하고 가장 가까운 곳에 있는 try-caatch문에서 처리해야 하는 것이고, throws는 자신의 메서드를 호출한 메서드로 에러객체를 던져서 처리를 위임하는 것!