계산기 단계별 구현하기
오늘은 이전 시간에 공부했던 내용들을 활용하여 계산기를 만들어보려고 합니다. 과제는 총 두개의 스텝으로 나누어 단계별로구현해볼 예정입니다.
STEP.1
■ 양의 정수(0 포함)를 입력받기
- Scanner를 사용하여 양의 정수 2개(0 포함)를 전달 받을 수 있습니다.
- 양의 정수는 각각 하나씩 전달 받습니다.
- 양의 정수는 적합한 타입으로 선언한 변수에 저장합니다.

■ 사칙연산 기호(➕,➖,✖️,➗)를 입력받기
- Scanner를 사용하여 사칙연산 기호를 전달 받을 수 있습니다.
- 사칙연산 기호를 적합한 타입으로 선언한 변수에 저장합니다. (charAt(0))

■ 위에서 입력받은 양의 정수 2개와 사칙연산 기호를 사용하여 연산을 진행한 후 결과값을 출력하기
- 키워드 : if switch
- 사칙연산 기호에 맞는 연산자를 사용하여 연산을 진행합니다.
- 입력받은 연산 기호를 구분하기 위해 제어문을 사용합니다. (예를 들면 if, switch)
- 연산 오류가 발생할 경우 해당 오류에 대한 내용을 정제하여 출력합니다.
- ex) “나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.“

■ 반복문을 사용하되, 반복의 종료를 알려주는 “exit” 문자열을 입력하기 전까지 무한으로 계산을 진행할 수 있도록 소스 코드를 수정하기
- 키워드 : 무한으로 반복, 수정하기 (처음부터 무한 반복하는 것이 아니라, 위 스텝별로 진행하며 수정)
- 반복문을 사용합니다. (예를 들어, for, while…)
오류 발생(트러블 슈팅)

위 사진 처럼 계산이 끝난 후, 사용자에게 계산을 계속 진행할지(Y) 종료할지(EXIT)를 입력받는 로직을 구현했습니다. 맨처음에 아래와 같은 코드를 작성하니 문제점이 생겼습니다. (← 문제 부분)
while (true) {
System.out.println("계산을 계속 진행하시겠습니까? (Y: 계속진행ㅣEXIT: 종료하기) : ");
String inputExitWheather = exitWheather.nextLine();
if (inputExitWheather.equalsIgnoreCase("Y")) {
break;
} else if (inputExitWheather.equalsIgnoreCase("EXIT")) {
break; // <--
// 예외처리: 입력 값이 Y도 아니고 EXIT도 아닐 때 출력
} else {
System.out.println("Y또는 EXIT를 입력해주시기 바랍니다.");
}
}
while (true) {
System.out.println("계산을 계속 진행하시겠습니까? (Y: 계속진행ㅣEXIT: 종료하기) : ");
String inputExitWheather = exitWheather.nextLine();
if (inputExitWheather.equalsIgnoreCase("Y")) {
break;
} else if (inputExitWheather.equalsIgnoreCase("EXIT")) {
continue; <--
// 예외처리: 입력 값이 Y도 아니고 EXIT도 아닐 때 출력
} else {
System.out.println("Y또는 EXIT를 입력해주시기 바랍니다.");
}
}
else if문 쪽에 break나 continue를 사용하여 반복문을 제어하려고 했지만 "EXIT"를 입력했음에도 불구하고 다시 계산이 진행되거나 종류 여부를 계속 물어보는 문제가 발생했었습니다.


문제의 원인은 break와 continue가 '현재 반복문만 제어한다'는 점을 명확히 이해하지 못했기 때문입니다. "EXIT"를 입력했을 때 종료하고 싶었던 것은 진행 여부를 묻는 반복문뿐만 아니라 전체 계산 흐름이었지만, break는 가장 가까운 반복문만 종료하기 때문에 원하는 프로그램 흐름제어가 되지 않았습니다.
해결 방법

그래서 반복문을 직접 종료하는 방식 대신, 프로그램의 상태를 나타내는 변수를 사용하기로 하였습니다. 위 사진처럼 8번째 줄에 complete라는 변수를 생성 후 false라는 값을 줬습니다.

그 후 else if에서 "EXIT"가 입력되면 complete를 true로 변경한 뒤 반복문 바깥에서 complete값을 기준으로 전체 흐름을 제어하도록 수정하였습니다.

수정 후 프로그램을 실행했을 때 모든 부분이 잘 작동하는것을 확인하실 수 있습니다.
배운 점
- break와 continue는 현재 반복문만 제어합니다.
- 반복문 제어만으로는 전체 프로그램 흐름을 관리하기 어렵습니다.
- 로직이 복잡해질수록 "상태 관리"가 중요하다는것을 배웠습니다.
STEP.2
이전에 만들었던 계산기에서 하나의 클래스에 모든 기능을 구현했었습니다. 하지만 해당 방식은 기능이 늘어날수록 코드가 복잡해진다는 한계가 있습니다. 이를 개선하기 위해 STEP2에서는 객체지향적인 설계 방식을 적용하여 문제를 풀어볼려고 합니다.
■ 사칙연산을 수행 후, 결과값 반환 메서드 구현 & 연산 결과를 저장하는 컬렉션 타입 필드를 가진 Calculator 클래스를 생성
- 사칙연산을 수행한 후, 결과값을 반환하는 메서드 구현
- 연산 결과를 저장하는 컬렉션 타입 필드를 가진 Calculator 클래스를 생성
- 1) 양의 정수 2개(0 포함)와 연산 기호를 매개변수로 받아 사칙연산(➕,➖,✖️,➗) 기능을 수행한 후, 2) 결과 값을 반환하는 메서드와 연산 결과를 저장하는 컬렉션 타입 필드를 가진 Calculator 클래스를 생성합니다.

문제와 같이 위 사진처럼 Calculator 클래스를 생성 후, 계산 기능을 담당하는 로직을 추가해보도록 하겠습니다.

먼저 double result = 0으로 변수를 선언하여 계산 결과를 저장할 수 있도록 하였습니다. 이후 switch-case 문을 통해 입력받은 연산자에 따라 각각의 case 문에서 연산을 수행하도록 구현하였습니다.
또한 곱셈의 경우 "*", "X", "x" 입력을 모두 허용하여 사용자가 다양한 방식으로 입력하더라도 문제없이 동작할 수 있도록 편의성을 고려하였습니다.
이와 같이 Calculator 클래스는 계산과 관련된 로직만 담당하도록 구성하였습니다.
■ STEP 1에서 구현한 App 클래스의 main 메서드에 Calculator 클래스가 활용될 수 있도록 수정
- 연산 수행 역할은 Calculator 클래스가 담당
- 연산 결과는 Calculator 클래스의 연산 결과를 저장하는 필드에 저장
- 소스 코드 수정 후에도 수정 전의 기능들이 반드시 똑같이 동작해야합니다.

먼저 Calculator 클래스를 사용하기 위해 App클래스에 Calculator라는 객체를 생성합니다.

그 후 입력받은 두개의 숫자와 연산자를 Calculator 객체에 전달하여 계산을 수행합니다. 계산은 Calculator클래스의 result 메서드에서 처리되며, 계산 결과는 반환값으로 전달 받습니다.
계산 결과가 정수인 경우와 실수인 경우, 구분하여 출력하게끔 결과 값에 소수점이 없는 경우에는 형변환을 통해 정수 형태로 출력하게끔 구현했습니다.
■ App 클래스의 main 메서드에서 Calculator 클래스의 연산 결과를 저장하고 있는 컬렉션 필드에 직접 접근하지 못하도록 수정 (캡슐화)
- 간접 접근을 통해 필드에 접근하여 가져올 수 있도록 구현합니다. (Getter 메서드)
- 간접 접근을 통해 필드에 접근하여 수정할 수 있도록 구현합니다. (Setter 메서드)
- 위 요구사항을 모두 구현 했다면 App 클래스의 main 메서드에서 위에서 구현한 메서드를 활용 해봅니다.
- Calculator 클래스에 저장된 연산 결과들 중 가장 먼저 저장된 데이터를 삭제하는 기능을 가진 메서드를 구현한 후 App 클래스의 main 메서드에 삭제 메서드가 활용될 수 있도록 수정
- 키워드 : 컬렉션
- 컬렉션에서 ‘값을 넣고 제거하는 방법을 이해한다.’가 중요합니다!

계산 결과를 저장하기 위해 위 사진처럼 AraayList<Double> 타입의 컬렉션 필드를 선언하였습니다. 해당 컬렉션은 여러 번 수행된 계산 결과를 순차적으로 저장하기 위한 용도입니다. 또한 App 클래스의 main 메서드에서 해당 컬렉션에 직접 접근하지 못하도록 private 접근제어자를 사용하여 제한하였습니다.

계산이 완료된 후에는 연산 결과를 미리 만들어둔 컬렉션에 저장합니다. 이를 통해 여러 번 수행된 계산 결과를 순차적으로 관리할 수 있도록 구성하였습니다. 또한 Getter와 Setter를 사용하여 Calculator 클래스의 연산 결과에 직접 접근하는 방식이 아닌, 간접적인 방식으로 조회하고 수정할 수 있도록 구현하였습니다.
removeCalculationResult 메서드는 컬렉션에 저장된 연산 결과 중 가장 먼저 저장된 데이터를 삭제하는 역할을 담당합니다. 이때 컬렉션이 비어 있는 경우를 고려하여 isEmpty 메서드를 사용함으로써 예외 상황이 발생하지 않도록 처리하였습니다.
이와 같이 객체지향적으로 코드를 작성하면 각 클래스의 역할과 책임이 명확해져 유지보수가 쉬워지고, 기능 확장 시 기존 코드에 미치는 영향을 최소화할 수 있습니다.
'TIL & 트러블 슈팅' 카테고리의 다른 글
| [내일배움캠프] - DAY12 제네릭, Enum, 람다, 스트림을 활용하여 계산기 개선하기 (0) | 2026.01.18 |
|---|---|
| [내일배움캠프] - DAY11 자바에 대해 알아보자-3 (0) | 2026.01.16 |
| [내일배움캠프] - DAY9 플로우차트 (0) | 2026.01.12 |
| [내일배움캠프] - DAY8 자바에 대해 알아보자-2 (0) | 2026.01.08 |
| [내일배움캠프] - DAY7 자바에 대해 알아보자-1 (0) | 2026.01.08 |
