사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
입력 문자열의 숫자와 사칙 연산 사이에는 반드시 빈 공백 문자열이 있다고 가정한다.
나눗셈의 경우 결과 값을 정수로 떨어지는 값으로 한정한다.
문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다.
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version> 3.22.0</version>
<scope>test</scope>
</dependency>
</dependencies>
위 의존성은 "junit", "assertj" 테스트 코드를 사용하기 위한 라이브러리이다.
public class CalculatorController {
// 연산을 위한 메서드
public int arithmetic(int firstNumber, char operatorSymbol, int secondNumber) {
if (operatorSymbol == '+') {
return add(firstNumber, secondNumber);
}
if (operatorSymbol == '-') {
return sub(firstNumber, secondNumber);
}
if (operatorSymbol == '/') {
return div(firstNumber, secondNumber);
}
if (operatorSymbol == '*') {
return mul(firstNumber, secondNumber);
}
return 0;
}
public int add(int firstNumber, int secondNumber) {
return firstNumber + secondNumber;
}
public int sub(int firstNumber, int secondNumber) {
return firstNumber - secondNumber;
}
public int div(int firstNumber, int secondNumber) {
return firstNumber / secondNumber;
}
public int mul(int firstNumber, int secondNumber) {
return firstNumber * secondNumber;
}
public int StringOfCalculate(String str) {
if (str.equals("0")) {
return 0;
}
if (!str.contains(" ")) {
return -1;
}
String[] value = str.split(" "); // 1 + 2면 value[0]에 1 value[1] + ...
int result = Integer.parseInt(value[0]);
for (int i=0; i < value.length-2; i=i+2) {
result = this.arithmetic(result,
value[i+1].charAt(0), Integer.parseInt(value[i+2]));
} return result;
}
}
str.equals("0") : 이 친구를 이용하여 0이 입력되면 프로그램을 종료하도록 설계하였다.
!str.contains(" ") : 공백을 이용하여 문자열을 가르는게 목표이기 때문에 공백을 포함하지 않으면 -1을 리턴시켜줘서 예외를 처리할 것이다.
String[] value = str.split(" "); : str을 공백을 통해 갈라서 배열에 저장할 것이다.
int result = Integer.parseInt(value[0]); : 먼저 result에 배열의 첫 번째 값을 저장할 것이다. 이유는 이어서 설명하겠다.
for (int i=0; i < value.length-2; i=i+2) {
result = this.arithmetic(result,
value[i+1].charAt(0), Integer.parseInt(value[i+2]));
여기서 첫 번째 값을 저장한 이유가 나오는데, result 대신 value[0 or i]값을 이용한다면 첫 번째 값만 들어가거나, i 가 2씩 증가해 결과값이 달라진다.
i+=2 한 이유는 배열에 값을 정확하게 찾기 위함이며, 그 이유로 value.length도 -2 해주어야 index 에러가 나타나지 않는다.
public class CalculatorService {
private Scanner scanner; // 스캐너로 입력 받은 값
private CalculatorController calculate;
public CalculatorService(Scanner scanner) {
this.scanner = scanner;
this.calculate = new CalculatorController();
}
public void run() throws IllegalArgumentException {
String inputArithmeticData = "";
boolean flag = true;
do {
System.out.print("입력 : ");
inputArithmeticData = scanner.nextLine();
String target = Optional.ofNullable(inputArithmeticData).orElse("");
if (target.isBlank()) {
throw new IllegalArgumentException();
}
int result = calculate.StringOfCalculate(inputArithmeticData);
if (result == -1) {
System.out.println("올바른 형식으로 입력해주세요.");
}
if (result != -1) {
System.out.println("결과 값은 : " + result);
}
if (result == 0) {
flag = false;
}
} while (flag);
}
}
isBlank() : java 11 이후 추가된 메서드, 문자열이 비어 있거나, 빈 공백으로만 이루어져 있으면, true를 리턴
isEmpty() : java 6 이후 추가된 메서드, 문자열의 길이가 0인 경우에, true를 리턴
public class CalculatorView {
private CalculatorService service;
public CalculatorView() {
this.service = new CalculatorService(new Scanner(System.in));
}
public void viewOfRun() {
System.out.println("===============문자열 계산기===============");
System.out.println();
System.out.println("문자열 연산을 하기위한 값을 / x + y / 형식으로 입력해주세요. * 종료 = 0 * ");
service.run();
}
}
public class Main {
public static void main(String[] args) throws IOException {
CalculatorView calculatorView = new CalculatorView();
calculatorView.viewOfRun();
}
}
@DisplayName("CalculatorMethodTest 클래스")
class CalculatorControllerTest {
private CalculatorController calculatorController;
@BeforeEach
void setup() {
calculatorController = new CalculatorController();
}
@Test
@DisplayName("연산 테스트")
void arithmeticTest() {
//given
String inputData = "1 + 2 / 3 * 4 - 5";
//when
int currentData = calculatorController.StringOfCalculate(inputData);
//then
assertThat(currentData).isEqualTo(-1);
}
}
class CalculatorServiceTest {
private CalculatorController calculatorController;
@BeforeEach
void setUp() {
calculatorController = new CalculatorController();
}
@Test
@DisplayName("run 메서드의 에러처리 테스트는")
void runTest() {
//given
String data = "";
String testData = Optional.ofNullable(data).orElse(" ");
//when, then
assertThatThrownBy(() -> assertThat(testData).isEqualTo(""))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("null이거나 빈 공백 문자입니다.");
}
}