Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

이지은님의 블로그

250108 - Java 계산기 Lv.2 및 Lv.3 구현 트러블슈팅: NaN 처리, 간접 접근, Switch 개선, 입력 문제 해결 본문

TIL

250108 - Java 계산기 Lv.2 및 Lv.3 구현 트러블슈팅: NaN 처리, 간접 접근, Switch 개선, 입력 문제 해결

queenriwon3 2025. 1. 8. 21:20

▷ 오늘 배운 것

계산기 과제 Lv.2와 Lv.3를 구현하면 생긴 문제에 관해 트러블 슈팅하는 내용을 작성해보려고 한다.

 

 

  1. 계산기에서 값을 출력할 수 없을 때 처리방법에 대하여
  2. 간접접근 활용
  3. 코드정렬을 하던 중 노란 줄을 발견했다.(retrurn switch)
  4. Lv.3에서 입력버퍼 문제 발생

 

 


 

 

1. 계산기에서 값을 출력할 없을 처리방법에 대하여

switch (oper) {
    case '+':
        return firstNum + secondNum;
    case '-':
        return firstNum - secondNum;
    case '*':
        return firstNum * secondNum;
    case '/':
        1f(secondNum = 0){
            System.out.printun("0으로 나눌 수 없습니다.");
            return 0;
        }
        return firstNum / secondNum;
    default:
        System.out.println("잘못된 연산자입니다.");
        return 0;
}

처음에 다음과 같은 코드를 작성했다. 평범하게 Calculator안에서 calculate()의 결과값을 switch로 리턴해주는 과정이다. 이때 다음과 같은 출력이 발생한다.

 

이 메소드를 호출한 곳에서 println(calculate())를 해줄 경우 0이 출력되고 만다. 일반적으로 두번째 피연산자를 0으로 설정하고 나눗셈을 하려고 하면 나누어지지 않아 결과값이 나오지 않는 것이 정상이다. 이때 이 메서드의 리턴 형식을 double로 해주었기 때문에 -1나 0으로 리턴하기에는 이 값을 결과값으로 알아보는 등 한계가 발생하고 만다.

 

 

그렇다면 어떻게 해결할 수 있을까?

 

일단 리턴값을 null 출력 하려고 했는데(return null), 반환 형식(double) 맞지 않다고 오류가 발생했다.

어떻게 출력할지 고민하던 와중 Double 래퍼 클래스에는 NaN값을 보장해준다는 것을 알게되었다.

 

return Double.NaN을 했을때 NaN이라고 그대로 출력됨

 

그럼 이때 NaN이라고 출력되는데 이것도 깔끔하지 않다. 이를 지워줄려면 main()에서 다음과 같이 NaN값에 대해 처리해주면 된다. 이렇게 하면 NaN값이 발생했을때 결과값을 출력하지 않는다.

if(!Double.isNaN(result)){ 
    System.out.println(result);
}

 

 

더욱 직관적인 방법도 있다. return대신 throw 예외를 던져 main()에서 예외를 처리해주면 된다.

// Calculator 클래스의 calculate()
case '/':
    if (secondNum == 0) {
        throw new ArithmeticException("0으로 나눌 수 없습니다.");
    }
    return firstNum / secondNum;


// App 클래스의 main()
try { 
	double result = calculator.calculate(operate, firstNumber, secondNumber); 
	System.out.println(result); 
} catch (ArithmeticException e) { 
	System.out.println(e.getMessage()); 
}

그러나 후자의 방법은 Lv.3에서 사용할 생각으로, Lv.2에서는 전자의 방법을 따랐다. 전자의 방법을 사용하면 다음과 같이 결과값이 출력되지 않고 0으로 나눌 없다는 안내만 출력되어 원하는 출려값을 얻을 수 있다.

 

 

 

2. 간접 접근 활용

Java에서 간접접근을 활용하기 위해서는 클래스의 필드  private로 설정(-)하고 이 필드를 public지정자 메서드(+)로 접근해야한다. 주어진 과제에서 간접접근은 OperateList클래스 안에서 getter setter 지정하는 것이 바람직해보인다.

class OperateList{
    private char operate;
    private double firstNumber;
    private double secondNumber;

    public OperateList() {
    }

    public char getOperate() { return operate;}
    public void setOperate(char operate) { this.operate = operate; }

    public double getFirstNumber() { return firstNumber;}
    public void setFirstNumber(double firstNumber) { this.firstNumber = firstNumber; }

    public double getSecondNumber() { return secondNumber; }
    public void setSecondNumber(double secondNumber) { this.secondNumber = secondNumber; }
}

 

이제 이 getter와 setter를 어떻게 사용할 것인가

 

ArrayList에 OperateList클래스를 추가하면서 다음과 같이 setter를 사용할 수 있으며,

저장된 ArrayList 요소를 가져와 연산을 할때 getter 사용했다. 사실 getter setter 사용하지 않고 충분히 구현할 수는 있지만 과제를 만족시키기 위해서 코드를 길게 작성한바 있다. 다음은 getter setter 작성한 부분이다.

// operateList 에 저장된 가장 최근 값을 가져옴
// 간접접근을 사용하여 값을 가져와(getter) 연산
int cur_index = operateList.size() - 1;
OperateList curOperate = operateList.get(cur_index);

char operate = curOperate.getOperate();
double firstNum = curOperate.getFirstNumber();
double secondNum = curOperate.getSecondNumber();

 

// 결과를 출력한 연산 저장
public void insertResult(char operate, double firstNumber, double secondNumber){

    // 간접접근을 사용하여 클래스 필드를 지정(setter)
    OperateList ol = new OperateList();
    ol.setOperate(operate);
    ol.setFirstNumber(firstNumber);
    ol.setSecondNumber(secondNumber);
    operateList.add(ol);
}

 

 

 

3. 코드 정렬을 하던 노란 줄을 발견했다.

Switch statement can be replaced with enhanced 'switch'

대충 해석하면 좀더 발전된 switch구문을 사용할 수 있다며, 코드를 바꿔준다는 것이다.

 

이 알림문을 발견한 것은 switch코드에서 발견할 수 있었다. (1번에서 봤던 switch문이다.)

 

더욱 발전된 switch문으로 자동작성해준다고 하여 이를 이용했더니 수정된 코드는 다음과 같았다.

 

수정된 코드는 코드 길이도 줄어졌고 한번에 switch구문을 반환할 수 있는 것 처럼 보였다.

거기에, switch return 합쳐서 람다문으로 작성 있는 같다. 이때 yield는반환값을양보하는데사용하는것같다.(return같은기능인데 return의하위에서사용되는듯하다.) 이렇게하면 return을 반복해서 사용하지 않고 필요한 곳에만 yield를 사용하면 된다는 장점이 생긴다.

손으로 순수한 코드는 아니지만 공부하고 구조를 익히기 위해 switch구문을 택했다.

 

 

 

 

4. Lv.3에서 입력 문제 발생

입력에관해 문제발생

Lv.3에서는 Lv.2를 더욱 확장시켜 저장한 결과값을 조회하는 기능이 생긴다. 먼저 계산식을 입력하라고 했을 때, lookup을 입력하면 데이터를 조회할 수 있는데, 1을 입력하면 연산자를 기준으로, 2을 입력하면 결과값을 기준으로 데이터를 조회할 수 있다. 

이때 정수를 입력해야하는데 다른 값을 입력해버리면 후로 입력이 제대로 먹지 않는 오류가 발생한다. 

 

 

수정전 코드는 다음과 같다.

이유는 입력값을 int로 받는 곳에 문자값을 입력했기 때문이다.

 

그러나 꼭 int로 받아야하는 이유는 없다. 그러므로 lookUpAns를 String으로 입력 받아야 제대로 된 의도를 가진 처리가 될 것 같다고 생각했다.

만약 int 받아야하는 값이라면 예외처리를 해주어서 해당 예외를 피해줄 수는 있다. 

 

수정 코드:

형을 String으로 통일해주고 입력버퍼에서 대해서도 수정을 해주면 입력에 관한 오류가 사라지는 것을 확인 할 수 있다.