이전 계산기 코드를 이용해서 예외처리를 하는 부분을 작성해보려고한다.
우리가 만든 Main은 숫자와 연산자를 입력하는 부분이 있었는데 이 부분을 CalculatorApp.java라는 신규 클래스로 분리를 할 예정이다.
public class Main {
public static void main(String[] args) {
boolean calculateEnded = false;
// 구현 2. 구현부분에 대해서는 과정을 진행하며 추가할 것이다.
}
}
이전 calculator에서는 calculate를 firstNumber, secondNumber라는 매개변수를 그냥 받아서 사용했었는데 이부분을 setter를 사용해서 값을 저장하는 방식을 사용한다.
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;
}
}
예외가 발생했을 때 나오는 구문을 만든 예외클래스이다.
public class BadInputException extends Exception {
public BadInputException(String type) {
super("잘못된 입력입니다! " + type + "을 입력해주세요!");
}
}
코드내부에서 주석으로 설명해보겠다.
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) {
// 구현 1.
}
public Parser parseSecondNum(String secondInput) {
// 구현 1.
}
public Parser parseOperator(String operationInput) {
// 구현 1.
}
public double executeCalculator() {
return calculator.calculate();
} // 계산실행하는 메소드
}
위에서 말한대로 main에서 scanner하던 부분을 따로 빼놓은 부분이다.
또한 반환값은 boolean으로 기본적으로 true를 반환한다.
import java.util.Scanner;
public class CalculatorApp {
public static boolean start() 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;
}
}
이제 구현부분을 해보자!

숙제 설명 4번에서 보았을 때 계산기의 로직을 전환시켜주는 곳이라고 하는 것을 보니 Operator가 어떤것이 들어오는지에 관해서 거기에 맞는 클래스를 호출해주는 부분이라고 보면될 것 같다.
또한 parser에 구현해야하는 부분이 3부분인데
하나는 첫번째 숫자, 두번째는 두번째 숫자, 세번째는 연산자 부분이다.
숫자 두개는 같은 코드일 것 같고 연산자 부분은 아까 말한대로 원하는 클래스를 호출해야하니 조건문을 사용해야겠다.
또한, 설명 8,9번에 Pattern.match() 메소드를 사용하라고 되어있는데 이에 대해 먼저 알아보도록 하겠다.
여기서 잠깐!
pattern.match??
우선 위에 parser 클래스를 봐보면 연산자랑 숫자값이 맞는지를 확인하기 위해 변수 선언해놓은 부분이 있다.
이것이 바로 정규식이라고 부르는 부분인데, 문자열의 검색과 치환을 위한 용도로 많이 사용된다고 한다.
(정규식의 사전적 의미 : 특정한 규칙을 가진 문자열의 집합을 표현하는데 사용하는 형식 언어)
이에 대해 정규 표현식에 대상 문자열을 검증하는 기능은 Pattern 클래스의 matches()메소드를 활용하는 것이다.
대상 문자열과 패턴이 일치하는지를 판단하여 boolean값을 반환한다.
사용하는 법은Pattern.matches(비교할문자, 비교할문자)와 같다.
public Parser parseFirstNum(String firstInput) throws BadInputException{
//BadInputException 클래스를 플래그로 세울거다 라는 것을 알려주기
// 구현 1.
if(!Pattern.matches(NUMBER_REG, firstInput)){
//pattern클래스를 이용해 숫자인지 확인하는 string과 입력받은 input을 비교
throw new BadInputException("정수");
//false일때는 해당 Exception은 throw하여 타입이 잘못됐다고 알림.
}
calculator.setFirstNumber(Integer.parseInt(firstInput));
return this;
}
위처럼 secondNumber도 코드를 짜고서, operator부분을 보아야한다.
똑같이 예외처리를 해준 뒤에 switch문을 사용해서 이전 계산기 코드처럼 해당 클래스를 호출해주면되지않을까?해서 만들어보았다.
public Parser parseOperator(String operationInput) throws BadInputException{
// 구현 1.
if(!Pattern.matches(OPERATION_REG, operationInput)){
throw new BadInputException("연산자");
}
switch (operationInput){
case "+":
calculator.setOperation(new AddOperation());
break;
case "-":
calculator.setOperation(new SubstractOperation());
break;
case "*":
calculator.setOperation(new MultiplyOperation());
break;
case "/":
calculator.setOperation(new DivideOperation());
break;
}
return this;
}
우선 이렇게 parser.java는 완성이 되었고 2번째로 가보아야겠다.
main에서는 그냥 app을 사용해서 start를 해주면 되지않을까? 해서
CalculatorApp.start();를 추가했더니 빨간줄이 생겼다.
확인해보니 start 메소드에 exception이 throw되어있었기 때문이었는데
이럴때는 try catch로 묶어서 예외처리를 해주면 문제없이 작동할 것이다.
(혹은 main메소드에 exception을 throws해줘도 되지않을까..?)
public class Main {
public static void main(String[] args){
boolean calculateEnded = false;
// 구현 2.
while (!calculateEnded) {
try {
CalculatorApp.start();
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
}
내가 만든 코드는 위와 같고 강사님과 거의 유사하지만 다른 부분이 있어서 한번 적어보려고한다.
이후에 배울 내용이긴하지만(모던자바) 람다식을 switch문에 작성하는 것이다.
위에 내가 작성한 parser.java를 보면
switch (operationInput){
case "+":
calculator.setOperation(new AddOperation());
break;
case "-":
calculator.setOperation(new SubstractOperation());
break;
case "*":
calculator.setOperation(new MultiplyOperation());
break;
case "/":
calculator.setOperation(new DivideOperation());
break;
}
이런식으로 작성되어있다. 사칙연산만 하기 때문에 몇개없어 괜찮지만 수가 많아지면 혹시 모를 break;를 빼고 작성을 해버린다던지, 조금 장황해보이는 느낌이나 에러 발생시 디버깅이 어렵다는 이유로 람다식을 사용하는 데 그 방법은 다음에 있을 포스트에서 할것이니 위 코드를 변경된 코드만 아래에 작성해보겠다.
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());
}
위 코드보다는 훨씬 간결해보이긴한다..!