[내일배움캠프] 계산기 구현 - 피드백 반영(3)

2024. 9. 18. 23:00내일배움캠프

 세 번째 피드백은 '0' 으로 피연산자를 나누는 연산에 대한 예외 처리'명확한 예외 처리' 에 대한 내용이었으며, 피드백을 반영한 코드는 여기서 확인할 수 있다.

 

1. 명확한 예외 처리

checkValidCalculation(String) 메서드

 

연산(입력 값)에 대한 유효성을 확인하는 'checkValidCalculation(String)' 메서드이다. 만약 유효하지 않다면 'BadInputException' 이 발생, 예외의 처리 책임은 메서드를 호출한 곳으로 넘긴다. 그래서 아래의 이미치처럼 발생한 예외를 'Level04.start()' 메서드에서 처리하도록 구현했다.

Level04.start() 메서드의 수행부 일부

 

문제의 구현부인데, 'InputValidator.checkValidCalculation()' 에서 발생한 예외를 'catch' 를 통해 잘 처리한 듯 보이지만 'catch' 에 지정된 예외가 최상위 예외인 'Exception' 이기에 'BadInputException' 이 아닌 어떤 예외가 발생해도 해당 'catch' 문을 통해 처리되어 버린다. "어? 예외가 전부 처리되면 좋은거 아니야?" 라는 생각을 할 수 있겠지만 그렇게 되면 정말 치명적인 예외를 식별하고 처리할 수가 없게 되어버린다. 그렇기에 의도적으로 발생시킨 예외든 처리하고자 하는 예외가 있다면 명확하게 해당 예외만을 처리하도록 'try-catch' 문을 작성하는 것이 좋다.

수정한 catch 문

 

이러한 구현 실수가 왜 생겼는지 되짚어 보니 구현 당시에 어떤 예외를 사용할지 정해진 것이 없는 상태에서 'Exception' 을 'catch' 에 지정해두고 이후 'BadInputException' 을 생성한 후 해당 부분을 수정하지 않았고 당시 "두 종류의 예외를 한 번에 처리해볼까?" 라는 생각도 있었기에 이러한 실수가 생긴 것으로 보인다.

 

 

2. '0' 으로 다른 피연산자를 나누는 경우의 예외 처리

 이것 또한 제대로 확인하지 못한 부분인데 '0' 으로 피연산자를 나누는 연산에 대한 예외 처리를 하지 않았다. 기본적으로 '0' 으로 나누는 연산을 막거나 예외를 처리했어야 했는데 이건 큰 실수이다.

 

정수(타입)의 경우 '0' 으로 나누는 연산을 수행시 ' ArithmeticException' 가 발생한다. 이는 'Infinity(무한대)' 를 정수로는 표현할 수 없기 때문이라 한다. 하지만 두 피연산자(x or 0) 중 하나라도 실수(타입)일 경우 예외가 발생하지 않고 'Infinity' 또는 'NaN(Not a Number)' 이 결과로 반환되는데 두 값은 이후 어떤 연산을 수행해도 결과가 'Infinity(or NaN)' 가 되므로  데이터를 엉망으로 만들 수 있다.

 

현재 구현한 계산기는 모두 실수형(double, Double) 을 사용하게끔 구현되어 있기 때문에 'Infinity' 와 'NaN' 에 대한 대책이 필요하다.

CalculationResultValidator 클래스 생성
DivideByZeroException 예외 클래스 생성

 

우선 연산 결과의 유효성을 검증하는 'CalculationResultValidator' 클래스를 생성하고 'checkDivideByZero(double)' 메서드를 작성해 결과가 'Infinity' 또는 'NaN' 인 경우 예외가 발생하도록 하였다. 사용할 예외로 'DivideByZeroException' 예외 클래스를 생성하였는데, 해당 예외는 미리 지정해둔 시스템 메시지를 갖도록 하였다.

Level04.start() 메서드에 연산결과 검증 로직 추가

 

Level04.start() 메서드에 연산결과를 검증하는 로직을 위의 이미지와 같이 추가하였다. 'CalculationResultValidator' 의 객체의 'checkDivideByZero(double)' 메서드를 호출해 연산 결과를 검증하고 연산결과가 'Infinity' 또는 'NaN' 일 경우 'DivideByZeroException' 이 발생, 'catch' 문에서 예외 메시지를 출력하고 'true' 를 반환한다.

 

또한 연산결과를 저장하는 로직은 'try-catch' 문 이후에 작성되어 있어 연산결과가 'Infinity' 또는 'NaN' 이라면 연산 결과는 '최근 연산 결과' 에 저장되지 않는다.

 

그리고 'Level04' 계산기까지 신경쓰지(파악하지) 못한 부분이기에 'Level01~03' 계산기 또한 해당 부분을 제대로 처리하지 못하고 있어 레벨별 요구사항에 맞춰 각 계산기를 수정하였다.