Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0c4e779
[add] String 클래스에 대한 학습 테스트 - 요구사항1
Hamliet Feb 5, 2020
c924385
[add] String 클래스에 대한 학습 테스트 - 요구사항2
Hamliet Feb 5, 2020
c82d818
[add] String 클래스에 대한 학습 테스트 - 요구사항3
Hamliet Feb 5, 2020
6806957
[add] Set Collection에 대한 학습 테스트 - 요구사항1
Hamliet Feb 5, 2020
8a1e511
[add] Set Collection에 대한 학습 테스트 - 요구사항2
Hamliet Feb 5, 2020
9ff5ba2
[add] 문자열 계산기 - README.md 파일 작성
Hamliet Feb 7, 2020
1b360a2
[add] 문자열 계산기 - 사용자로부터 입력받기
Hamliet Feb 7, 2020
addb5c7
[add] 문자열 계산기 - 홀수 인덱스와 짝수 인덱스로 나누는 함수
Hamliet Feb 7, 2020
47cf992
[add] 문자열 계산기 - 부호에 따라 계산하는 함수 구현
Hamliet Feb 7, 2020
3de7961
[add] 문자열 계산기 - 사칙연산에 해당하는 각 함수 구현
Hamliet Feb 7, 2020
09addca
[add] 문자열 계산기 - 입력값을 확인하는 핸들러 구현
Hamliet Feb 7, 2020
889a3c6
[mod] 문자열 계산기 - 정수형으로 계산하던 것을 실수형으로 확장
Hamliet Feb 7, 2020
d1ea865
[add] 문자열 계산기 - 홀수 인덱스와 짝수 인덱스로 나누는 함수 단위 테스트
Hamliet Feb 7, 2020
0b53410
[add] 문자열 계산기 - 부호에 따라 계산하는 함수 단위 테스트
Hamliet Feb 7, 2020
c295110
[add] 문자열 계산기 - 사칙연산에 해당하는 각 함수 단위 테스트
Hamliet Feb 7, 2020
750daac
[add] 문자열 계산기 - 입력값을 확인하는 핸들러 단위 테스트
Hamliet Feb 7, 2020
a517723
[add] 문자열 계산기 - 0으로 나눌 경우 처리
Hamliet Feb 7, 2020
8133b04
[mod] 문자열 계산기 - 입력값을 확인하는 핸들러 단위 테스트
Hamliet Feb 7, 2020
c2994fc
Merge pull request #1 from aegis1920/onboarding
aegis1920 Feb 7, 2020
1576729
mod : @Displayname 추가
aegis1920 Feb 7, 2020
ba76416
mod : 패키지, 클래스 분리 및 view 클래스 생성
aegis1920 Feb 8, 2020
b0881d4
mod : util 패키지 추가
aegis1920 Feb 8, 2020
11373d9
mod : 강제 형변환 -> Math 클래스 이용
aegis1920 Feb 8, 2020
917bd64
del : 테스트 클래스 안에 있는 서비스 코드
aegis1920 Feb 8, 2020
21c17f3
mod : 입출력 분리
aegis1920 Feb 9, 2020
187f90b
add : Operator를 Enum으로 분리, refactor : 함수명과 Calculator 클래스 리펙토링
aegis1920 Feb 9, 2020
41209de
add : 테스트코드 재작성 및 static으로 인한 get set 메서드 추가
aegis1920 Feb 9, 2020
141f92b
add : isEven, isOdd 메서드 추가
aegis1920 Feb 10, 2020
838427e
refactor : checkSign 메서드
aegis1920 Feb 10, 2020
7df937b
refactor : Operator 인자 수정
aegis1920 Feb 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# java-calculator
문자열 계산기 미션 저장소

## 우아한테크코스 코드리뷰
* [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
# 문자열 계산기
## 요구사항
- 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
- 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다.
- 예를 들어 "2 + 3 * 4 / 2"와 같은 문자열을 입력할 경우 2 + 3 * 4 / 2 실행 결과인 10을 출력해야 한다.
## 추가할 기능 목록
1. 사용자로부터 입력받기
2. 홀수 인덱스와 짝수 인덱스로 나누는 함수
1. 짝수 인덱스일 때는 부호를 저장하는 로직
2. 홀수 인덱스일 경우에는 계산하는 함수 호출
3. 부호에 따라 계산하는 함수 구현
4. 사칙연산에 해당하는 각 함수 구현
5. 입력값을 확인하는 핸들러 구현
1. 양식에 맞지 않을 경우 (부호가 연속, 숫자가 연속으로 나올 경우)
2. [예외 처리] 0으로 나눌 경우
8 changes: 8 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import calculator.domain.Calculator;

public class Application {
public static void main(String[] args){
Calculator calculator = new Calculator();
calculator.run();
}
}
76 changes: 76 additions & 0 deletions src/main/java/calculator/domain/Calculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package calculator.domain;

import calculator.view.InputView;
import calculator.view.OutputView;

public class Calculator {
private static final int INDEX_INIT = 1;
private static final int FIRST_VALUE_INDEX = 0;
private static final int EVEN_NUMBER = 0;
private static final int ODD_NUMBER = 1;
private static final String DELIMITER = " ";
static double returnValue;
static String nowSign;

public void setNowSign(String sign) {
this.nowSign = sign;
}

public void setReturnValue(double returnValue) {
this.returnValue = returnValue;
}

public double getReturnValue() {
return this.returnValue;
}

public String getNowSign() {
return this.nowSign;
}

public static void run() {
String[] values = InputView.inputHandler().split(DELIMITER);
returnValue = Double.parseDouble(values[FIRST_VALUE_INDEX]);
selectOddNumberOrEvenNumber(values);
OutputView.printResult(returnValue);
}

public static void selectOddNumberOrEvenNumber(String[] values) {
for (int i = INDEX_INIT; i < values.length; i++) {
calculateEvenNumber(i, values[i]);
calculateOddNumber(i, values[i]);
}
}

public static boolean isOdd(int number) {
return number % 2 == ODD_NUMBER;
}

public static boolean isEven(int number) {
return number % 2 == EVEN_NUMBER;
}
Comment on lines +45 to +51
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


public static void calculateOddNumber(int index, String value) {
if (isOdd(index)) {
nowSign = value;
}
}

public static void calculateEvenNumber(int index, String value) {
if (isEven(index)) {
selectOperators(Double.parseDouble(value));
}
}

public static void selectOperators(double nowNumber) {
for (Operator operators : Operator.values()) {
calculateNumber(operators, nowNumber);
}
}

public static void calculateNumber(Operator operators, double nowNumber) {
if (operators.getOperator().equals(nowSign)) {
returnValue = operators.calculate(nowNumber, returnValue);
}
}
}
26 changes: 26 additions & 0 deletions src/main/java/calculator/domain/Operator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package calculator.domain;

import java.util.function.BiFunction;

public enum Operator {
PLUS("+", (nowNumber, returnValue) -> returnValue + nowNumber),
MINUS("-", (nowNumber, returnValue) -> returnValue - nowNumber),
MULTIPLY("*", (nowNumber, returnValue) -> returnValue * nowNumber),
DIVIDE("/", (nowNumber, returnValue) -> returnValue / nowNumber);
Comment on lines +6 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


private String operator;
private BiFunction<Double, Double, Double> expression;

Operator(String operator, BiFunction<Double, Double, Double> expression) {
this.operator = operator;
this.expression = expression;
}

public double calculate(double nowNumber, double returnValue) {
return expression.apply(nowNumber, returnValue);
}

public String getOperator() {
return this.operator;
}
}
65 changes: 65 additions & 0 deletions src/main/java/calculator/util/ExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package calculator.util;


import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import static calculator.domain.Calculator.isEven;
import static calculator.domain.Calculator.isOdd;

public class ExceptionHandler {
private static final int EVEN = 0;
private static final String DELIMITER = " ";
private static final String BLANK = " ";
private static final String EMPTY_STRING = "";
private static final String NUMBER_FORMAT = "-?\\d+(\\.\\d+)?";
private static final String DIVIDE_ZERO_STRING = "/0";
private static List<String> operatorList = Arrays.asList("+", "-", "*", "/");

public static String checkInputHandler(String input) {
if (checkString(input.split(DELIMITER)) == true && checkUndefinedValue(input) == true) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 보통 if 안에 들어가는 조건식 메소드 명을 명시적으로 짓고, 따로 ture/false체크를 안하는 편입니다.
이중 체크라는 생각이 들어서요...

if (checkString(input.split(DELIMITER)) && checkUndefinedValue(input))

우테코 과정을 진행하면서 다른 분들과 의견을 나누어 보세요!

return input;
}
throw new IllegalArgumentException();
}

public static boolean checkUndefinedValue(String str) {
if (str.replace(BLANK, EMPTY_STRING).contains(DIVIDE_ZERO_STRING)) {
return false;
}
return true;
}

public static boolean checkString(String[] inputStrings) {
if (inputStrings.length % 2 == EVEN) {
return false;
}

AtomicInteger index = new AtomicInteger();
return Arrays.stream(inputStrings)
.allMatch(str -> checkIndividual(index.getAndIncrement(), str));
}

public static boolean checkIndividual(int i, String inputString) {
if (isEven(i)) {
return checkNumber(inputString);
}
if (isOdd(i)) {
return checkSign(inputString);
}
return false;
}

public static boolean checkNumber(String inputString) {
return inputString.matches(NUMBER_FORMAT);
}

public static boolean checkSign(String inputString) {
if (operatorList.contains(inputString)) {
return true;
}
return false;
Comment on lines +58 to +62
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래처럼 줄여도 되지 않을까요?

public static boolean checkSign(String inputString) {
    return operatorList.contains(inputString);
}

}

}
31 changes: 31 additions & 0 deletions src/main/java/calculator/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package calculator.view;

import java.util.InputMismatchException;
import java.util.Scanner;

import static calculator.util.ExceptionHandler.checkInputHandler;

public class InputView {

private static Scanner scanner = new Scanner(System.in);
private static final String INPUT_EXPRESSION_STR = "식을 입력해주세요 : ";
private static final String CHECK_INPUT_STR = "입력값을 확인해주세요!";

public static String inputHandler() {
try {
return checkInputHandler(printInputExpression());
} catch (InputMismatchException | IllegalArgumentException e) {
printInputCheck();
return inputHandler();
}
}

public static String printInputExpression(){
System.out.print(INPUT_EXPRESSION_STR);
return scanner.nextLine();
}

public static void printInputCheck(){
System.out.println(CHECK_INPUT_STR);
}
}
11 changes: 11 additions & 0 deletions src/main/java/calculator/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package calculator.view;

public class OutputView {
public static void printResult(double result){
String printFormat = "결과는 %f 입니다.";
if(result == Math.floor(result)){
printFormat = "결과는 %.0f 입니다.";
}
System.out.printf(printFormat, result);
}
}
Empty file removed src/main/java/empty.txt
Empty file.
66 changes: 66 additions & 0 deletions src/test/java/calculator/CalculatorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package calculator;

import calculator.domain.Calculator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static calculator.domain.Calculator.*;
import static org.assertj.core.api.Assertions.*;

public class CalculatorTest {
static final double TEST_RETURN_VALUE_INIT = 10;
static final String TEST_NOW_SIGN_INIT = "+";
Calculator calculator = new Calculator();

@BeforeEach
void setUp() {
calculator.setReturnValue(TEST_RETURN_VALUE_INIT);
calculator.setNowSign(TEST_NOW_SIGN_INIT);
}

static Stream<Arguments> stringArrayProvider() {
return Stream.of(
Arguments.of(new String[]{"4", "*", "3", "/", "5", "-", "20"}, -17.6),
Arguments.of(new String[]{"2", "-", "1", "*", "3", "+", "2"}, 5)
);
}

@ParameterizedTest
@MethodSource("stringArrayProvider")
@DisplayName("문자열을 받아 계산하는 메서드")
void selectOddNumberOrEvenNumberTest(String[] values, double expected) {
calculator.setReturnValue(Double.parseDouble(values[0]));
selectOddNumberOrEvenNumber(values);
assertThat(calculator.getReturnValue()).isEqualTo(expected);
}

@ParameterizedTest
@CsvSource(value = {"0:-:+", "1:*:*", "3:-:-"}, delimiter = ':')
@DisplayName("인덱스가 홀수면 부호를 저장하는 메서드")
void calculateOddNumberTest(int index, String value, String expected) {
calculator.calculateOddNumber(index, value);
assertThat(calculator.getNowSign()).isEqualTo(expected);
}

@ParameterizedTest
@CsvSource(value = {"0:1:11", "2:2.3:12.3", "3:4.0:10"}, delimiter = ':')
@DisplayName("인덱스가 짝수면 계산하는 메서드")
void calculateEvenNumberTest(int index, String value, double expected) {
calculator.calculateEvenNumber(index, value);
assertThat(calculator.getReturnValue()).isEqualTo(expected);
}

@ParameterizedTest
@CsvSource(value = {"1:11", "2.3:12.3", "4.0:14.0"}, delimiter = ':')
@DisplayName("연산자에 따라 계산하는 메서드")
void selectOperatorsTest(double value, double expected) {
calculator.selectOperators(value);
assertThat(calculator.getReturnValue()).isEqualTo(expected);
}
}
53 changes: 53 additions & 0 deletions src/test/java/calculator/ExceptionHandlerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package calculator;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicInteger;

import static calculator.util.ExceptionHandler.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class ExceptionHandlerTest {

@Test
@DisplayName("입력값을 체크해주는 테스트")
public void checkInputHandlerTest() {
String str = "321 + 3 + f";
assertThatThrownBy(() -> {
checkInputHandler(str);
}).isInstanceOf(IllegalArgumentException.class);
}

@Test
@DisplayName("문자열을 split하고 전체적으로 체크해주는 테스트")
void checkStringTest() {
String[] inputStrings = "333 + 2434343".split(" ");
assertThat(checkString(inputStrings)).isTrue();
}

@Test
@DisplayName("숫자인지 체크해주는 테스트")
void checkNumberTest() {
String str = "g";
assertThat(checkNumber(str)).isFalse();
}

@Test
@DisplayName("사칙연산인지 체크해주는 테스트")
void checkSignTest() {
String str = "@";
assertThat(checkSign(str)).isFalse();
}

@Test
@DisplayName("0으로 나누었을 때의 예외처리를 해주는 테스트")
void checkUndefinedValueTest() {
String str = "0 / 0";
assertThat(checkUndefinedValue(str)).isFalse();
}
}
Loading