계산기 과제 트러블슈팅
트러블 슈팅 개요
- 문제상황 : 어떤 현상을 발견해서
- 해결과정 : 다음과 같이 해결하였고
- 회고 : 해결하는 과정에서 다음을 깨달았다.
[문제상황]
1. 결과값을 저장하는 resultArray가 계산이 다시 수행될 때 마다 다른 리스트에 저장되는 현상이 일어났다.
2. level2 까지 과제를 구현한 후 다시 요구사항에 맞게 구현하였는지 다시 검토하였다. 다시 검토해 본 결과 다음과 같은 문제를 발견할 수 있었다.
- 2-1. 요구사항에 맞춰 getter,setter 함수를 구현하였지만 정작 함수를 이용하지 않고 있었다. 다음은 App클래스에서 사용하지 않던 함수이다.
- getter함수 : 리스트의 값을 반환
- setter함수 : 특정 인덱스의 값을 특정 값으로 수정
- removeResult함수 : 0번째 인덱스의 값을 수정
- 2-2. 연산자를 String으로 입력받고 있었지만 요구사항에는 char로 입력받도록 명시하고 있었다. 또한 charAt함수를 이용하여야했다.
- 2-3. 숫자를 입력받는 단계에서 실수를 입력받을 시 예외처리에 대한 부분을 구현하지 않았다.
- 2-4. 연산자를 입력받는 부분에서 +,-*,/ 이외의 값이 들어올 경우에 대한 예외처리를 구현하지 않았다.
[해결과정]
1.
계산을 이어서 수행할 경우 계산의 결과 값이 서로 다른 리스트에 저장되어 계산결과가 기록되지 않았다.
fullGetter함수를 이용해 값을 확인해 본 결과 각 계산기 객체마다 다른 리스트로 저장되어 값이 하나씩 밖에 저장되어 있지 않았다.
따라서 계산결과값을 저장하는 resultArray필드를 멤버변수가 아닌 클래스변수로 선언하여 각 객체들이 계산 결과를 하나의 리스트에서 공유할 수 있도록 수정하였다.
//객체 간의 계산결과를 공유하기 위해서 static 키워드 사용
static private List<Integer> resultArray = new ArrayList<Integer>();
2-1.
다음은 요구사항에 맞춰 구현한 메서드이다.
//계산 메서드
public void calculate(int firstNumber, int secondNumber, char operator) {
Scanner sc = new Scanner(System.in);
if(operator == '+'){
this.result = firstNumber + secondNumber;
} else if (operator == '-') {
this.result = firstNumber - secondNumber;
} else if (operator == '*') {
this.result = firstNumber * secondNumber;
} else if (operator == '/') {
if(secondNumber == 0){
System.out.println("나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.");
System.out.println("첫번째 숫자: " + firstNumber);
System.out.println("두번째 숫자를 다시 입력하세요: ");
secondNumber = sc.nextInt();
}
this.result = firstNumber / secondNumber;
}
resultArray.add(this.result);
};
public List<Integer> getter() {
return resultArray;
}
public void setter(int index, int value) {
resultArray.set(index, value);
};
public void printResult() {
System.out.println("계산 결과는 " + resultArray.get(resultArray.size()-1) + "입니다.");
}
public void removeResult() {
resultArray.remove(0);
}
public void fullGetter() {
System.out.println(resultArray.toString());
};
getter 함수는 리스트에 값이 없는 경우를 확인하기 위해서 다음과 같이 사용하였다.
if(doCalculate.getter().isEmpty()) {
System.out.println("기록된 계산결과가 없습니다. 삭제를 종료합니다.");
break;
}
setter함수는 계산결과기록을 수정하는 기능에서 다음과 같이 사용하였다.
else if (removeAnswer.equals("edit")) {
while(true) {
System.out.println("현재까지 기록된 계산결과입니다.");
doCalculate.fullGetter();
System.out.println("수정하고 싶은 결과의 인덱스를 입력하세요.(0부터 시작): ");
int editIndex = sc.nextInt();
System.out.println("어떤 값으로 수정하시겠습니까? 값을 입력하세요.: ");
int editValue = sc.nextInt();
doCalculate.setter(editIndex, editValue);
System.out.println("수정된 계산 결과입니다.");
doCalculate.fullGetter();
System.out.println("계속 수정을 원할 경우 1을 입력하세요. 수정을 종료하고 싶다면 0을 입력하세요.: ");
int editInt = sc.nextInt();
if(editInt == 1) {
continue;
} else if (editInt == 0) {
break;
}
}
removeResult함수는 계산결과기록을 삭제하는 기능에서 다음과 같이 사용하였다.
System.out.println("계산결과를 삭제하고 싶다면 remove를 입력하세요.\n계산결과를 수정하고 싶다면 edit을 입력하세요.\n그렇지 않다면 아무 키나 입력하세요: " );
String removeAnswer = sc.next();
if(removeAnswer.equals("remove")) {
while(true) {
System.out.println("현재까지 기록된 계산결과입니다.");
doCalculate.fullGetter();
if(doCalculate.getter().isEmpty()) {
System.out.println("기록된 계산결과가 없습니다. 삭제를 종료합니다.");
break;
}
System.out.println("가장 첫번째 결과부터 삭제됩니다.\n삭제를 원하면 1을 입력하세요. 삭제를 종료하고 싶다면 0을 입력하세요.: ");
int removeInt = sc.nextInt();
if(removeInt == 1) {
doCalculate.removeResult();
} else if (removeInt == 0) {
break;
}
}
2-2.
초반엔 연산자를 String으로 입력받았다. 그러나 요구사항에 맞춰 char로 입력받기 위해 다음과 같이 수정하였다.
char operator;
while (true) {
try {
String inputOperator = sc.next();
if (inputOperator.isEmpty()) {
System.out.println("계산할 연산자를 입력하세요.: ");
sc.nextLine();
continue;
그리고 charAt함수를 이용하여 0번째 인덱스의 값을 가져오도록 하였다.
operator = inputOperator.charAt(0);
String으로 입력받아서 유효한 연산자인지 검증하면 되는데 왜 굳이 charAt(0)으로 값을 받아와야하는지에 대해서 생각해보았다.
사용자가 값을 잘못입력 할 시(예: 연산자 2개 입력, 연산자입력 후 공백문자) 올바른 연산자를 추출하기 위해 그 중에서 0번째 인덱스의 연산자를 가져오겠다는 의미로 해석하였다.
2-3.
수를 입력받는 부분에서 음수인 부분은 if문을 이용해 처리하였지만 실수 값을 입력받을 시 nextInt()으로 값을 입력받기 때문에 발생하는 오류를 해결하지 않았다. 따라서 다음과 같이 예외처리문을 작성하였다.
while (true) {
try {
firstNumber = sc.nextInt();
if (firstNumber < 0) {
System.out.println("0을 포함한 양수를 입력하세요.");
System.out.println("계산할 첫번째 숫자을 입력하세요.(0을 포함한 양의 정수): ");
sc.nextLine();
continue;
}
break;
} catch (Exception e) {
System.out.println("정수를 입력하세요.");
System.out.println("계산할 첫번째 숫자을 입력하세요.(0을 포함한 양의 정수): ");
sc.nextLine();
}
}
2-4.
연산자를 입력받는 부분에서 유요한 연산자 이외에 값을 입력해도 임의로 계산이 되어버리는 예외가 발생했다. 따라서 유효한 연산자만 입력하도록 예외처리문을 작성하였다.
while (true) {
try {
String inputOperator = sc.next();
if (inputOperator.isEmpty()) {
System.out.println("계산할 연산자를 입력하세요.: ");
sc.nextLine();
continue;
}
operator = inputOperator.charAt(0);
if (operator != '+' && operator != '-' && operator != '*' && operator != '/') {
System.out.println("입력할 수 있는 연산자는 오직 +,-,*,/ 입니다.");
System.out.println("계산할 연산자를 입력하세요.: ");
sc.nextLine();
continue;
}
break;
}
catch (Exception e) {
System.out.println("유효하지 않은 입력입니다. 입력할 수 있는 연산자는 오직 +,-,*,/ 입니다.");
System.out.println("계산할 연산자를 입력하세요.: ");
}
}
[회고]
초반엔 요구사항에 맞게 잘 구현하였다고 생각했었다. 그러나 입력예외들을 생각해보면서 상당히 많은 부분에서 에러를 발생하고 예외를 처리해주는 부분이 없다는 것을 발견하게 되었다. 또한 함수를 요구사항에 맞게 구현했지만 쓸모없는 함수를 구현하라는 뜻이 아니라 요구사항에 맞게 구현해서 사용하라는 뜻이었다.
생각보다 유효하지 않은 입력에 대해서 예외처리를 해야할 부분이 많았었다. 그리고 지금보다 예외처리문을 깔끔하게 수정할 필요하 있어보인다.
그리고 git에 push할때 과제1, 과제2완료 등이 아닌 기능별로 커밋하고 push해서 기능별로 분기를 만드는 것이 더 좋았겠다고 생각된다.