[문제]
package com.project.personal.calculator;
public class Calculator {
public Calculator() {
}
public int calculate(int numOne, String operator, int numTwo) {
if (operator.equals("+")) {
return numOne + numTwo;
} else if (operator.equals("-")) {
return numOne - numTwo;
} else if (operator.equals("*")) {
return numOne * numTwo;
} else {
if (numTwo == 0) {
return 0;
// [문제] 분모에 0이 들어가면 0이 나올 수 없는데?
// 반환타입이 정수형인 int라 문자열 못 쓰잖아?
} else {
return numOne / numTwo;
}
}
}
}
나누기를 할 땐 분모에 0이 들어가면 안 되기 때문에 두 번째 숫자인 numTwo에 0을 입력하면 '분모에 해당하는 두 번째 숫자에 0이 들어가서 나누기 연산이 되지 않았습니다.' 안내문구를 출력하고 싶었다. 문제는 반환타입을 정수형인 int로 정했기 때문에, 안내문구 같은 문자열을 반환할 수 없었다. 클래스 없이 계산기를 만들 땐 이 문제를 겪지 않은 터라, 왜 발생했을까 자연스레 의문이 들었다.
[원인]
원인은 바로 예외 처리할 때 쓰이는 try-catch문을 배우지 않은 데 있었다. 클래스가 없을 때야 if문과 else if문을 중첩해서 뚝딱뚝딱 만들었다면, 지금은 얘기가 달랐다. 당장 try-catch문이 뭔지 본 다음 코드를 작성하면 좋았겠지만, 우선 배운 지식을 최대한 활용하고 싶었다. int를 void로 바꾸어서 일일이 System.out.println();라고 쓰기보다는 현재 작성한 if문을 살리고 싶었다. 튜터님 또한 의견이 같았고, if문을 활용해서 구현하기로 했다.
[해결]
// [1] 클래스 Calculator에서 반환값 수정
package com.project.personal.calculator;
public class Calculator {
public Calculator() {
}
public int calculate(int numOne, String operator, int numTwo) {
if (operator.equals("+")) {
return numOne + numTwo;
} else if (operator.equals("-")) {
return numOne - numTwo;
} else if (operator.equals("*")) {
return numOne * numTwo;
} else {
if (numTwo == 0) {
return -127;
// [수정 전] 0
// [수정 후] -127
// [수정 근거] 조건상 0 이상인 정수만 입력해야 한다.
// 그러니까 나오기 힘든 값을 이용하자!
} else {
return numOne / numTwo;
}
}
}
}
우선 Calculator 클래스에서 반환할 값으로 0 대신 -127, 즉 음수를 입력했다.
// [2] Main에서 if문과 else문 추가
package com.project.personal.calculator;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("0 이상인 첫 번째 정수를 입력해 주세요: ");
int numFirst = sc.nextInt();
// [수정 전] 첫 번째 숫자
// [수정 후] 0 이상인 첫 번째 정수
// [수정 근거 1] 사용자가 정확한 값을 입력할 수 있도록 안내문구 수정
// [수정 근거 2] 예외처리를 완벽하게 할 수 없는 데 따른 대안으로 수정
System.out.print("사칙연산 기호(+, -, *, /) 중 하나를 입력해 주세요: ");
String operator = sc.next();
System.out.print("0 이상인 두 번째 정수를 입력해 주세요: ");
int numSecond = sc.nextInt();
// [수정 전] 두 번째 숫자
// [수정 후] 0 이상인 두 번째 정수
// [수정 근거 1] 사용자가 정확한 값을 입력할 수 있도록 안내문구 수정
// [수정 근거 2] 예외처리를 완벽하게 할 수 없는 데 따른 대안으로 수정
Calculator test = new Calculator();
int result = test.calculate(numFirst, operator, numSecond);
// [수정 후]
if (result == -127) {
System.out.println("나눗셈 연산에서 분모(두 번째 정수)에 0은 올 수 없습니다.");
} else {
String outcome = Integer.toString(result);
System.out.println("연산한 결과는 "+outcome+"입니다.");
}
// [수정 전]
// String outcome = Integer.toString(result);
// System.out.println("연산한 결과는 "+outcome+"입니다.");
}
}
그다음으로는 Main으로 돌아가서 -127이 반환되었을 때는 두 번째 정수에 0이 들어갔다는 안내문구가 나오도록 if문을 작성했고, 그렇지 않다면 else문 안에 적은 대로 연산한 결과가 출력되도록 코드를 수정했다.
현재 공부한 내용만으로는 완벽하게 예외처리를 하기 어렵다는 점이 내심 아쉬웠다. 지금처럼 코드를 작성한다면, 뺄셈을 한 결과값이 -127이 나와서 나눗셈이 안 되었다는 안내문구가 출력될 수 있었기 때문이다. 내일까지 개인 프로젝트를 잘 마무리 짓고 빨리 4주 차 강의를 들어야겠다는 의욕이 싹을 틔웠다. try-catch문도 조만간 꼭 정복할 거다.
[24.11.20 추가] -127 대신 Integer.MIN_VALUE를 넣어서 예외 처리 문제를 해결하는 방법도 있었다. Integer.MIN_VALUE는 말 그대로 정수의 최솟값을 의미하기에 두 정수끼리 더하든 빼든 곱하든 나누든 했을 때 나올 확률이 거의 없는 값이나 마찬가지였다. 팀원분의 제안을 들은 동시에 클래스와 메인 속 -127을 지우고 Integer.MIN_VALUE를 입력했다.
[결과 수치화]
두 정수 모두 0 이상이기 때문에 나눗셈에서 -127 또는 마찬가지로 음수인 Integer.MIN_VALUE가 나올 확률은 0이었으나, 두 번째 정수가 첫 번째 정수보나 너무 큰 나머지 뺄셈에서 예외 처리용 값이 나올 수 있었다. 어떻게 결과를 수치화할지 고민하다가 챗GPT를 활용하여 정수의 각 범위가 0부터 2147483648까지라는 가정하에, -127이 나올 확률과 Integer.MIN_VALUE가 나올 확률을 구했다.
[수정 전] 뺄셈에서 예외 처리용 결괏값이 나올 수 있는 두 정수 선택지 2147483522개
[수정 후] 뺄셈에서 예외 처리용 결괏값이 나올 수 있는 두 정수 선택지 1개
'Troubleshooting: 무엇이 문제였는가? > 본캠프 2주 차: 계산기 만들기' 카테고리의 다른 글
2단계: "반복문 안에서 인스턴스화를 했다고요? 갑부시군요!" (0) | 2024.11.24 |
---|---|
2단계: 절차 지향 add() vs 객체 지향 add() (0) | 2024.11.20 |
2단계: sc.nextLine(); vs sc.next(); (0) | 2024.11.19 |
2단계: 비교 연산자(==) vs equals() (0) | 2024.11.19 |