From 823468f0312c4865c8324e27ce1c2f8ad4383ab7 Mon Sep 17 00:00:00 2001 From: heenahan Date: Mon, 5 Jun 2023 17:26:20 +0900 Subject: [PATCH 01/34] =?UTF-8?q?init=20:=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EC=B4=88=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 218 ++++++++++++++++++ app/src/main/java/com/programmers/App.java | 14 ++ .../test/java/com/programmers/AppTest.java | 14 ++ settings.gradle | 17 ++ 4 files changed, 263 insertions(+) create mode 100644 .gitignore create mode 100644 app/src/main/java/com/programmers/App.java create mode 100644 app/src/test/java/com/programmers/AppTest.java create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..626fc284b --- /dev/null +++ b/.gitignore @@ -0,0 +1,218 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Gradle template +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + diff --git a/app/src/main/java/com/programmers/App.java b/app/src/main/java/com/programmers/App.java new file mode 100644 index 000000000..dbff89188 --- /dev/null +++ b/app/src/main/java/com/programmers/App.java @@ -0,0 +1,14 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.programmers; + +public class App { + public String getGreeting() { + return "Hello World!"; + } + + public static void main(String[] args) { + System.out.println(new App().getGreeting()); + } +} diff --git a/app/src/test/java/com/programmers/AppTest.java b/app/src/test/java/com/programmers/AppTest.java new file mode 100644 index 000000000..166d15564 --- /dev/null +++ b/app/src/test/java/com/programmers/AppTest.java @@ -0,0 +1,14 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.programmers; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class AppTest { + @Test void appHasAGreeting() { + App classUnderTest = new App(); + assertNotNull(classUnderTest.getGreeting(), "app should have a greeting"); + } +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..ad51c31a5 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,17 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/8.1.1/userguide/multi_project_builds.html + * This project uses @Incubating APIs which are subject to change. + */ + +plugins { + // Apply the foojay-resolver plugin to allow automatic download of JDKs + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0' +} + +rootProject.name = 'java-calculator' +include('app') From 9f99b959c7d235c11551a0a4605005870056654c Mon Sep 17 00:00:00 2001 From: heenahan Date: Fri, 9 Jun 2023 09:57:42 +0900 Subject: [PATCH 02/34] =?UTF-8?q?feat=20:=20=EC=A4=91=EC=9C=84=20=ED=91=9C?= =?UTF-8?q?=EA=B8=B0=EC=8B=9D=EC=9D=84=20=ED=9B=84=EC=9C=84=20=ED=91=9C?= =?UTF-8?q?=EA=B8=B0=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80=ED=99=98?= =?UTF-8?q?=ED=95=B4=EC=84=9C=20=EA=B3=84=EC=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../programmers/calculator/Calculator.java | 65 +++++++++++++++++++ .../com/programmers/calculator/Operator.java | 42 ++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 app/src/main/java/com/programmers/calculator/Calculator.java create mode 100644 app/src/main/java/com/programmers/calculator/Operator.java diff --git a/app/src/main/java/com/programmers/calculator/Calculator.java b/app/src/main/java/com/programmers/calculator/Calculator.java new file mode 100644 index 000000000..fcc3e62e2 --- /dev/null +++ b/app/src/main/java/com/programmers/calculator/Calculator.java @@ -0,0 +1,65 @@ +package com.programmers.calculator; + +import java.util.*; + +public class Calculator { + + public List changeInfixToPostfix(List infix) { + List postfix = new ArrayList<>(); + Stack stack = new Stack<>(); + + for (String s : infix) { + if (s.matches("\\d+")) { // 숫자일 경우 + postfix.add(s); + } else { // 숫자 아닐 경우 + int priority = getPriority(s); + // 스택이 비었거나 + while (!stack.isEmpty()) { + String topOperator = stack.peek(); + int topPriority = getPriority(topOperator); + + // top의 우선 순위가 높거나 같을 경우 + if (topPriority >= priority) postfix.add(stack.pop()); + // top의 우선 순위가 낮을 경우 + else break; + } + stack.push(s); // 연산자 넣음 + } + } + + // 스택에 남아있는 연산자 모두 집어 넣음 + while (!stack.isEmpty()) postfix.add(stack.pop()); + + return postfix; + } + + public Integer calcPostfix(List postfix) { + Stack stack = new Stack<>(); + + for (String s : postfix) { + // 숫자일 경우 스택에 넣음 + if (s.matches("\\d+")) stack.push(Integer.parseInt(s)); + else { // 연산자 일 경우 + Integer op1 = stack.pop(); + Integer op2 = stack.pop(); + + Operator calc = Operator.of(s); + Integer result = calc.getFunc().apply(op2, op1); + + stack.push(result); + + System.out.println(stack.size()); + } + } + + return stack.pop(); + } + + public Integer getPriority(String operator) { + // * 와 / 는 우선순위 높음 + if (operator.equals("*") || operator.equals("/")) return 1; + // 그 외 낮음 + return -1; + } + +} diff --git a/app/src/main/java/com/programmers/calculator/Operator.java b/app/src/main/java/com/programmers/calculator/Operator.java new file mode 100644 index 000000000..82003dc09 --- /dev/null +++ b/app/src/main/java/com/programmers/calculator/Operator.java @@ -0,0 +1,42 @@ +package com.programmers.calculator; + +import java.util.Arrays; +import java.util.function.BiFunction; + +public enum Operator { + + PLUS("+", (a, b) -> { return a + b; }), + MINUS("-", (a, b) -> { return a - b; }), + DIVIDE("/", (a, b) -> { + try { + return a / b; + } catch (ArithmeticException e) { + throw e; + } + }), + MUTIPLY("*", (a, b) -> { return a * b; }); + + private String operator; + private BiFunction func; + + Operator(String operator, BiFunction func) { + this.operator = operator; + this.func = func; + } + + public String getOperator() { + return operator; + } + + public BiFunction getFunc() { + return func; + } + + public static Operator of(String operator) { + return Arrays.stream(Operator.values()) + .filter(o -> o.getOperator().equals(operator)) + .findFirst() + .orElseThrow(NullPointerException::new); + } + +} From c78db4c1ac5a655964edda214878edca3d25a5e9 Mon Sep 17 00:00:00 2001 From: heenahan Date: Fri, 9 Jun 2023 09:58:39 +0900 Subject: [PATCH 03/34] =?UTF-8?q?test=20:=20=EC=82=AC=EC=B9=99=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../programmers/calculator/OperatorTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 app/src/test/java/com/programmers/calculator/OperatorTest.java diff --git a/app/src/test/java/com/programmers/calculator/OperatorTest.java b/app/src/test/java/com/programmers/calculator/OperatorTest.java new file mode 100644 index 000000000..637d1337c --- /dev/null +++ b/app/src/test/java/com/programmers/calculator/OperatorTest.java @@ -0,0 +1,61 @@ +package com.programmers.calculator; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; + +import java.util.function.BiFunction; + +import static org.assertj.core.api.Assertions.*; + +class OperatorTest { + + @Test + @DisplayName("연산자에 따라 제대로 계산") + void exactlyCalc() { + // given + Integer op1 = 6; Integer op2 = 2; + String[] operators = { "+", "-", "*", "/" }; + Integer[] results = { 8, 4, 12, 3 }; + + for (int i = 0; i < 4; i++) { + // when + Operator calc = Operator.of(operators[i]); + BiFunction func = calc.getFunc(); + + // then + assertThat(func.apply(op1, op2)) + .isEqualTo(results[i]); + } + } + + @Test + @DisplayName("이상한 연산자가 들어갈 경우 NullPointException 던짐") + void throwNullPointerExceptionWhenoddOperator() { + // given + String oddOperator = "!"; + + assertThatThrownBy(() -> { + // when + Operator.of(oddOperator); + // then + }).isExactlyInstanceOf(NullPointerException.class); + } + + @Test + @DisplayName("0으로 나누는 경우 ArithmeticException 던짐") + void throwWhenDivideZero() { + // given + Integer op1 = 4; Integer op2 = 0; + Operator calc = Operator.of("/"); + BiFunction func = calc.getFunc(); + + assertThatThrownBy(() -> { + // when + func.apply(op1, op2); + // then + }).isExactlyInstanceOf(ArithmeticException.class); + } + +} \ No newline at end of file From 4e840f1675593a6e1334cb48a6c84d5b163f1904 Mon Sep 17 00:00:00 2001 From: heenahan Date: Fri, 9 Jun 2023 09:59:23 +0900 Subject: [PATCH 04/34] =?UTF-8?q?test=20:=20=ED=9B=84=EC=9C=84=ED=91=9C?= =?UTF-8?q?=EA=B8=B0=EC=8B=9D=20=EB=B3=80=ED=99=98=20=ED=9B=84=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/CalculatorTest.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 app/src/test/java/com/programmers/calculator/CalculatorTest.java diff --git a/app/src/test/java/com/programmers/calculator/CalculatorTest.java b/app/src/test/java/com/programmers/calculator/CalculatorTest.java new file mode 100644 index 000000000..159a7cdaa --- /dev/null +++ b/app/src/test/java/com/programmers/calculator/CalculatorTest.java @@ -0,0 +1,56 @@ +package com.programmers.calculator; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +class CalculatorTest { + + Calculator calculator = new Calculator(); + + @Test + @DisplayName("중위 표기식을 후위 표기식으로 변환") + void infixTopostfix() { + // given + List infix1 = List.of("1", "*", "2", "+", "3", "/", "4"); + + // when + List postfix = calculator.changeInfixToPostfix(infix1); + + // then + assertThat(postfix) + // 순서도 똑같이 + .containsExactly("1", "2", "*", "3", "4", "/", "+"); + } + + @Test + @DisplayName("후위 표기식을 계산") + void calcPostfix() { + // given + List postfix = List.of("1", "2", "*", "4", "2", "/", "+"); + + // when + Integer answer = calculator.calcPostfix(postfix); + + // then + assertThat(answer).isEqualTo(4); + } + + @Test + @DisplayName("연산자 우선 순위 계산") + void isPriority() { + // given + String[] operator = { "+", "-", "*", "/" }; + int[] expectedPriority = { -1, -1, 1, 1 }; + + // when + for (int i = 0; i < 4; i++) { + int priority = calculator.getPriority(operator[i]); + assertThat(priority).isEqualTo(expectedPriority[i]); + } + } + +} \ No newline at end of file From 27c00314410291c4cf2f2c2b1624431d55b2f345 Mon Sep 17 00:00:00 2001 From: heenahan Date: Fri, 9 Jun 2023 10:00:56 +0900 Subject: [PATCH 05/34] =?UTF-8?q?feat=20:=20=EC=97=B0=EC=82=B0=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EB=A7=B5=EC=97=90=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/programmers/storage/Storage.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 app/src/main/java/com/programmers/storage/Storage.java diff --git a/app/src/main/java/com/programmers/storage/Storage.java b/app/src/main/java/com/programmers/storage/Storage.java new file mode 100644 index 000000000..eb7341a6b --- /dev/null +++ b/app/src/main/java/com/programmers/storage/Storage.java @@ -0,0 +1,20 @@ +package com.programmers.storage; + +import com.programmers.expression.Expression; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class Storage { + + static Map map = new ConcurrentHashMap<>(); + + public void save(Expression expression, Integer result) { + map.put(expression.toString(), result); + } + + public Map findAll() { + return map; + } + +} From bb2ba063eaaab98d9e58aafc58419549fa386f61 Mon Sep 17 00:00:00 2001 From: heenahan Date: Fri, 9 Jun 2023 10:03:55 +0900 Subject: [PATCH 06/34] =?UTF-8?q?feat=20:=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=EC=97=B0=EC=82=B0=EC=9D=84=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=97=B0=EC=82=B0=EC=9C=BC=EB=A1=9C=20=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../programmers/expression/Expression.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 app/src/main/java/com/programmers/expression/Expression.java diff --git a/app/src/main/java/com/programmers/expression/Expression.java b/app/src/main/java/com/programmers/expression/Expression.java new file mode 100644 index 000000000..4a14a45a2 --- /dev/null +++ b/app/src/main/java/com/programmers/expression/Expression.java @@ -0,0 +1,26 @@ +package com.programmers.expression; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class Expression { + + private List expression; + + public Expression(String expression) { + this.expression = Arrays.stream(expression.split(" ")) + .collect(Collectors.toList()); + } + + public List getExpression() { + return expression; + } + + public String toString() { + return expression.stream() + .collect(Collectors.joining(" ")); + } + +} From 104c54bb42c192e873b04474ab951b1bcd8f3201 Mon Sep 17 00:00:00 2001 From: heenahan Date: Fri, 9 Jun 2023 10:05:25 +0900 Subject: [PATCH 07/34] =?UTF-8?q?test=20:=20=EC=A0=80=EC=9E=A5=EC=86=8C,?= =?UTF-8?q?=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EC=97=B0=EC=82=B0=EC=9D=84=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=97=B0=EC=82=B0=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=ED=99=98=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expression/ExpressionTest.java | 42 +++++++++++++++++++ .../com/programmers/storage/StorageTest.java | 33 +++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 app/src/test/java/com/programmers/expression/ExpressionTest.java create mode 100644 app/src/test/java/com/programmers/storage/StorageTest.java diff --git a/app/src/test/java/com/programmers/expression/ExpressionTest.java b/app/src/test/java/com/programmers/expression/ExpressionTest.java new file mode 100644 index 000000000..38f46e53c --- /dev/null +++ b/app/src/test/java/com/programmers/expression/ExpressionTest.java @@ -0,0 +1,42 @@ +package com.programmers.expression; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +class ExpressionTest { + + @Test + @DisplayName("문자열 연산을 리스트 연산으로 바꾸어준다.") + void changeStrExpressionToListExpression() { + // given + String strExpression = "3 * 4 / 2"; + + // when + Expression expression = new Expression(strExpression); + List listExpression = expression.getExpression(); + + // then + assertThat(listExpression) + .containsExactly("3", "*", "4", "/", "2"); + } + + @Test + @DisplayName("리스트 연산을 문자열 연산으로 변환한다.") + void changeListExpressionToStrExpression() { + // given + Expression expression = new Expression("3 * 4 / 2"); + + // when + String strExpression = expression.toString(); + + // then + assertThat(strExpression) + .isEqualTo("3 * 4 / 2"); + } + +} \ No newline at end of file diff --git a/app/src/test/java/com/programmers/storage/StorageTest.java b/app/src/test/java/com/programmers/storage/StorageTest.java new file mode 100644 index 000000000..b88b1870c --- /dev/null +++ b/app/src/test/java/com/programmers/storage/StorageTest.java @@ -0,0 +1,33 @@ +package com.programmers.storage; + +import com.programmers.expression.Expression; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.*; + +class StorageTest { + + Storage storage = new Storage(); + + @Test + @DisplayName("저장을 한다") + void save() { + // given + Expression expression = new Expression("1 * 2"); + int result = 3; + + // when + storage.save(expression, result); + Map list = storage.findAll(); + + // then + assertThat(list) + .isNotEmpty() + .containsExactly(entry("1 * 2", 3)); + } + +} \ No newline at end of file From 91ae6e6fd5e3d5569cae7da16c717eb10667d283 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 10 Jun 2023 23:34:36 +0900 Subject: [PATCH 08/34] =?UTF-8?q?chore=20:=20=EC=B6=9C=EB=A0=A5=EB=AC=B8?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/programmers/calculator/Calculator.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/programmers/calculator/Calculator.java b/app/src/main/java/com/programmers/calculator/Calculator.java index fcc3e62e2..51dde94c8 100644 --- a/app/src/main/java/com/programmers/calculator/Calculator.java +++ b/app/src/main/java/com/programmers/calculator/Calculator.java @@ -47,8 +47,6 @@ public Integer calcPostfix(List postfix) { Integer result = calc.getFunc().apply(op2, op1); stack.push(result); - - System.out.println(stack.size()); } } From dd891534ba61acd96a8f065e827378781751f18e Mon Sep 17 00:00:00 2001 From: heenahan Date: Sun, 11 Jun 2023 00:24:55 +0900 Subject: [PATCH 09/34] =?UTF-8?q?feat=20:=20=EC=9C=A0=ED=9A=A8=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=9E=85=EB=A0=A5=EA=B0=92?= =?UTF-8?q?=EC=9D=80=20=EC=98=88=EC=99=B8=20=EB=8D=98=EC=A7=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/programmers/expression/Expression.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/programmers/expression/Expression.java b/app/src/main/java/com/programmers/expression/Expression.java index 4a14a45a2..df410d117 100644 --- a/app/src/main/java/com/programmers/expression/Expression.java +++ b/app/src/main/java/com/programmers/expression/Expression.java @@ -1,6 +1,5 @@ package com.programmers.expression; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -10,6 +9,7 @@ public class Expression { private List expression; public Expression(String expression) { + isValid(expression); this.expression = Arrays.stream(expression.split(" ")) .collect(Collectors.toList()); } @@ -18,6 +18,10 @@ public List getExpression() { return expression; } + public void isValid(String expression) { + if (!expression.matches("([0-9] [+|-|*|/] )+[0-9]")) throw new IllegalArgumentException(); + } + public String toString() { return expression.stream() .collect(Collectors.joining(" ")); From 73a262d41ce52bd844816f26ede0447713602b61 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sun, 11 Jun 2023 00:43:47 +0900 Subject: [PATCH 10/34] =?UTF-8?q?feat=20:=20DB=EC=9D=80=20=EB=B6=88?= =?UTF-8?q?=EB=B3=80=ED=95=B4=EC=95=BC=20=ED=95=98=EB=AF=80=EB=A1=9C=20fin?= =?UTF-8?q?al?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/programmers/storage/Storage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/programmers/storage/Storage.java b/app/src/main/java/com/programmers/storage/Storage.java index eb7341a6b..7d2453dc6 100644 --- a/app/src/main/java/com/programmers/storage/Storage.java +++ b/app/src/main/java/com/programmers/storage/Storage.java @@ -7,7 +7,7 @@ public class Storage { - static Map map = new ConcurrentHashMap<>(); + private final static Map map = new ConcurrentHashMap<>(); public void save(Expression expression, Integer result) { map.put(expression.toString(), result); From e4a7702765595489972bdf44e4a12b39a4375490 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sun, 11 Jun 2023 00:45:57 +0900 Subject: [PATCH 11/34] =?UTF-8?q?test=20:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=EC=88=98=EC=8B=9D=EC=9D=B4=20=EC=9E=85=EB=A0=A5=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EC=98=88=EC=99=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expression/ExpressionTest.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/app/src/test/java/com/programmers/expression/ExpressionTest.java b/app/src/test/java/com/programmers/expression/ExpressionTest.java index 38f46e53c..099f3bba7 100644 --- a/app/src/test/java/com/programmers/expression/ExpressionTest.java +++ b/app/src/test/java/com/programmers/expression/ExpressionTest.java @@ -1,6 +1,5 @@ package com.programmers.expression; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -38,5 +37,25 @@ void changeListExpressionToStrExpression() { assertThat(strExpression) .isEqualTo("3 * 4 / 2"); } - + + @Test + @DisplayName("잘못된 입력은 예외를 던진다.") + void throwWhenInvalidInput() { + // given + String[] invalidInput = { + "1 + 1", + "1 + ", + " + 1", + " " + }; + + for (String s : invalidInput) { + assertThatThrownBy(() -> { + // when + Expression expression = new Expression(s); + // then + }).isExactlyInstanceOf(IllegalArgumentException.class); + } + } + } \ No newline at end of file From 88acf06462b425848a3030c879ce0c1bb2d375c7 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sun, 11 Jun 2023 00:53:03 +0900 Subject: [PATCH 12/34] =?UTF-8?q?feat=20:=20=EC=9E=85=EB=A0=A5=EA=B3=BC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/programmers/ui/InputView.java | 16 +++++++ .../java/com/programmers/ui/OutputView.java | 43 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 app/src/main/java/com/programmers/ui/InputView.java create mode 100644 app/src/main/java/com/programmers/ui/OutputView.java diff --git a/app/src/main/java/com/programmers/ui/InputView.java b/app/src/main/java/com/programmers/ui/InputView.java new file mode 100644 index 000000000..0d697d8a6 --- /dev/null +++ b/app/src/main/java/com/programmers/ui/InputView.java @@ -0,0 +1,16 @@ +package com.programmers.ui; + +import java.io.BufferedReader; +import java.io.IOException; + +public class InputView { + + public String select(BufferedReader br) throws IOException { + return br.readLine(); + } + + public String expression(BufferedReader br) throws IOException { + return br.readLine(); + } + +} diff --git a/app/src/main/java/com/programmers/ui/OutputView.java b/app/src/main/java/com/programmers/ui/OutputView.java new file mode 100644 index 000000000..8dcaf2694 --- /dev/null +++ b/app/src/main/java/com/programmers/ui/OutputView.java @@ -0,0 +1,43 @@ +package com.programmers.ui; + +import java.util.Map; + +public class OutputView { + + public void init() { + System.out.println("1. 조회"); + System.out.println("2. 계산"); + } + + public void viewResult(Integer result) { + System.out.println(result); + } + + public void viewList(Map list) { + for (String expression : list.keySet()) { + Integer result = list.get(expression); + System.out.println(expression + " = " + result); + } + } + + public void eof() { + System.out.println("프로그램을 종료합니다."); + } + + public void inputInOneAndTwo() { + System.out.println("입력은 1과 2만 가능합니다."); + } + + public void inputIsOnlyNumber() { + System.out.println("입력은 오직 숫자만 가능합니다."); + } + + public void divideByZeroException() { + System.out.println("0으로 나눌 수 없습니다."); + } + + public void invalidInputException() { + System.out.println("잘못된 입력입니다."); + } + +} From 46aed93cc224b073165c4f75a0bfc1a7e6663c66 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sun, 11 Jun 2023 00:54:15 +0900 Subject: [PATCH 13/34] =?UTF-8?q?feat=20:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/programmers/App.java | 11 +-- .../controller/CalculatorController.java | 70 +++++++++++++++++++ 2 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/programmers/controller/CalculatorController.java diff --git a/app/src/main/java/com/programmers/App.java b/app/src/main/java/com/programmers/App.java index dbff89188..2462201cc 100644 --- a/app/src/main/java/com/programmers/App.java +++ b/app/src/main/java/com/programmers/App.java @@ -3,12 +3,13 @@ */ package com.programmers; -public class App { - public String getGreeting() { - return "Hello World!"; - } +import com.programmers.controller.CalculatorController; +public class App { + public static void main(String[] args) { - System.out.println(new App().getGreeting()); + CalculatorController calculatorController = new CalculatorController(); + calculatorController.run(); } + } diff --git a/app/src/main/java/com/programmers/controller/CalculatorController.java b/app/src/main/java/com/programmers/controller/CalculatorController.java new file mode 100644 index 000000000..0be922e1d --- /dev/null +++ b/app/src/main/java/com/programmers/controller/CalculatorController.java @@ -0,0 +1,70 @@ +package com.programmers.controller; + +import com.programmers.calculator.Calculator; +import com.programmers.expression.Expression; +import com.programmers.storage.Storage; +import com.programmers.ui.InputView; +import com.programmers.ui.OutputView; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Map; + +public class CalculatorController { + + private InputView inputView = new InputView(); + private OutputView outputView = new OutputView(); + private Calculator calculator = new Calculator(); + private Storage storage = new Storage(); + + public void run() { + try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + while (true) { + outputView.init(); + String select = inputView.select(br); + if (!isValidInput(select)) continue; + Integer num = Integer.parseInt(select); + if (num.equals(1)) view(); + else if (num.equals(2)) calculate(br); + else { + outputView.inputInOneAndTwo(); + continue; + } + } + } catch (IOException e) { + outputView.eof(); + } + } + + private boolean isValidInput(String select) throws IOException { + if (select.isEmpty()) throw new IOException(); + if (!select.matches("[0-9]+")){ + outputView.inputIsOnlyNumber(); + return false; + } return true; + } + + private void calculate(BufferedReader br) throws IOException { + try { + String str = inputView.expression(br); + Expression expression = new Expression(str); + List postfix = calculator.changeInfixToPostfix(expression.getExpression()); + Integer result = calculator.calcPostfix(postfix); + storage.save(expression, result); + outputView.viewResult(result); + } catch (IllegalArgumentException e) { + outputView.invalidInputException(); + } catch (ArithmeticException e) { + outputView.divideByZeroException(); + } + } + + private void view() { + Map list = storage.findAll(); + outputView.viewList(list); + } + +} From ef913ecaa3019265cebcc5709ce68a2135377c6e Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:01:34 +0900 Subject: [PATCH 14/34] =?UTF-8?q?docs=20:=20gradle=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 app/build.gradle diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 000000000..c64ae18c9 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,48 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java application project to get you started. + * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle + * User Manual available at https://docs.gradle.org/8.1.1/userguide/building_java_projects.html + * This project uses @Incubating APIs which are subject to change. + */ + +plugins { + // Apply the application plugin to add support for building a CLI application in Java. + id 'application' +} + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // This dependency is used by the application. + implementation 'com.google.guava:guava:31.1-jre' + + // https://mvnrepository.com/artifact/org.assertj/assertj-core + testImplementation 'org.assertj:assertj-core:3.24.2' +} + +testing { + suites { + // Configure the built-in test suite + test { + // Use JUnit Jupiter test framework + useJUnitJupiter('5.9.1') + } + } +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } +} + +application { + // Define the main class for the application. + mainClass = 'com.programmers.App' +} From 679a10726543db46b028798c6b1af873fb885b51 Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:04:29 +0900 Subject: [PATCH 15/34] =?UTF-8?q?refactor=20:=20=EC=9A=B0=EC=84=A0?= =?UTF-8?q?=EC=88=9C=EC=9C=84=20enum=EC=97=90=EC=84=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20enum=20=EC=95=88=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=82=AC=EC=B9=99=20=EC=97=B0=EC=82=B0=20=EC=88=98=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/programmers/util/Operator.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 app/src/main/java/com/programmers/util/Operator.java diff --git a/app/src/main/java/com/programmers/util/Operator.java b/app/src/main/java/com/programmers/util/Operator.java new file mode 100644 index 000000000..608c29596 --- /dev/null +++ b/app/src/main/java/com/programmers/util/Operator.java @@ -0,0 +1,47 @@ +package com.programmers.util; + +import com.programmers.exception.DivisionByZeroException; +import com.programmers.exception.NotFoundOperatorException; + +import java.util.Arrays; +import java.util.function.BiFunction; + +public enum Operator { + + PLUS("+", -1, (a, b) -> { return a + b; }), + MINUS("-", -1, (a, b) -> { return a - b; }), + DIVIDE("/", 1, (a, b) -> { + try { + return a / b; + } catch (ArithmeticException e) { + throw new DivisionByZeroException("0으로 나눌 수 없습니다."); + } + }), + MUTIPLY("*", 1, (a, b) -> { return a * b; }); + + private final String operator; + private final int priority; + private final BiFunction calculation; + + Operator(String operator, int priority, BiFunction calculation) { + this.operator = operator; + this.priority = priority; + this.calculation = calculation; + } + + public static Operator of(String operator) { + return Arrays.stream(Operator.values()) + .filter(o -> o.operator.equals(operator)) + .findFirst() + .orElseThrow(() -> new NotFoundOperatorException("찾을 수 없는 연산자입니다.")); + } + + public int getPriority() { + return priority; + } + + public Integer calculateOperation(Integer op1, Integer op2) { + return calculation.apply(op1, op2); + } + +} From b00a4fbbeaded95ad12ecf393aab01d57e0e60e1 Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:05:29 +0900 Subject: [PATCH 16/34] =?UTF-8?q?refactor=20:=20=EC=9E=90=EB=A3=8C?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20stack=20->=20deque?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../programmers/calculator/Calculator.java | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/programmers/calculator/Calculator.java b/app/src/main/java/com/programmers/calculator/Calculator.java index 51dde94c8..f4ffef450 100644 --- a/app/src/main/java/com/programmers/calculator/Calculator.java +++ b/app/src/main/java/com/programmers/calculator/Calculator.java @@ -1,63 +1,64 @@ package com.programmers.calculator; +import com.programmers.util.Operator; + import java.util.*; +import java.util.regex.Pattern; public class Calculator { + private final Pattern NUMBER = Pattern.compile("\\d+"); + public List changeInfixToPostfix(List infix) { List postfix = new ArrayList<>(); - Stack stack = new Stack<>(); + Deque deque = new ArrayDeque<>(); - for (String s : infix) { - if (s.matches("\\d+")) { // 숫자일 경우 - postfix.add(s); - } else { // 숫자 아닐 경우 - int priority = getPriority(s); - // 스택이 비었거나 - while (!stack.isEmpty()) { - String topOperator = stack.peek(); - int topPriority = getPriority(topOperator); - - // top의 우선 순위가 높거나 같을 경우 - if (topPriority >= priority) postfix.add(stack.pop()); - // top의 우선 순위가 낮을 경우 - else break; + infix.stream() + .forEach(s -> { + if (NUMBER.matcher(s).matches()) { // 숫자일 경우 + postfix.add(s); + } else { // 숫자 아닐 경우 + Operator operator = Operator.of(s); + int priority = operator.getPriority(); + // 덱이 비었거나 + while (!deque.isEmpty()) { + Operator topOperator = Operator.of(deque.peekLast()); + int topPriority = topOperator.getPriority(); + + // top의 우선 순위가 높거나 같을 경우 + if (topPriority >= priority) postfix.add(deque.pollLast()); + // top의 우선 순위가 낮을 경우 + else break; + } + deque.addLast(s); // 연산자 넣음 } - stack.push(s); // 연산자 넣음 - } - } + }); // 스택에 남아있는 연산자 모두 집어 넣음 - while (!stack.isEmpty()) postfix.add(stack.pop()); + while (!deque.isEmpty()) postfix.add(deque.pollLast()); return postfix; } - public Integer calcPostfix(List postfix) { - Stack stack = new Stack<>(); + public Integer calculatePostfix(List postfix) { + Deque deque = new ArrayDeque<>(); - for (String s : postfix) { - // 숫자일 경우 스택에 넣음 - if (s.matches("\\d+")) stack.push(Integer.parseInt(s)); - else { // 연산자 일 경우 - Integer op1 = stack.pop(); - Integer op2 = stack.pop(); - - Operator calc = Operator.of(s); - Integer result = calc.getFunc().apply(op2, op1); - - stack.push(result); - } - } + postfix.stream() + .forEach(s -> { + // 숫자일 경우 덱에 넣음 + if (NUMBER.matcher(s).matches()) deque.addLast(Integer.parseInt(s)); + else { // 연산자 일 경우 + Integer op1 = deque.pollLast(); + Integer op2 = deque.pollLast(); + + Operator calc = Operator.of(s); + Integer result = calc.calculateOperation(op2, op1); + + deque.addLast(result); + } + }); - return stack.pop(); - } - - public Integer getPriority(String operator) { - // * 와 / 는 우선순위 높음 - if (operator.equals("*") || operator.equals("/")) return 1; - // 그 외 낮음 - return -1; + return deque.pollLast(); } } From 9a70dfaa819001c00dd09cb115d876d85ca799ba Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:07:04 +0900 Subject: [PATCH 17/34] =?UTF-8?q?feat=20:=20custom=20exception=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/AbnormalTerminationException.java | 11 +++++++++++ .../exception/DivisionByZeroException.java | 9 +++++++++ .../exception/InvalidFormulaException.java | 9 +++++++++ .../programmers/exception/NotFoundMenuException.java | 9 +++++++++ .../exception/NotFoundOperatorException.java | 9 +++++++++ .../com/programmers/exception/NotNumberException.java | 9 +++++++++ 6 files changed, 56 insertions(+) create mode 100644 app/src/main/java/com/programmers/exception/AbnormalTerminationException.java create mode 100644 app/src/main/java/com/programmers/exception/DivisionByZeroException.java create mode 100644 app/src/main/java/com/programmers/exception/InvalidFormulaException.java create mode 100644 app/src/main/java/com/programmers/exception/NotFoundMenuException.java create mode 100644 app/src/main/java/com/programmers/exception/NotFoundOperatorException.java create mode 100644 app/src/main/java/com/programmers/exception/NotNumberException.java diff --git a/app/src/main/java/com/programmers/exception/AbnormalTerminationException.java b/app/src/main/java/com/programmers/exception/AbnormalTerminationException.java new file mode 100644 index 000000000..e8a6e142e --- /dev/null +++ b/app/src/main/java/com/programmers/exception/AbnormalTerminationException.java @@ -0,0 +1,11 @@ +package com.programmers.exception; + +import java.io.IOException; + +public class AbnormalTerminationException extends IOException { + + public AbnormalTerminationException(String message) { + super(message); + } + +} diff --git a/app/src/main/java/com/programmers/exception/DivisionByZeroException.java b/app/src/main/java/com/programmers/exception/DivisionByZeroException.java new file mode 100644 index 000000000..a723be491 --- /dev/null +++ b/app/src/main/java/com/programmers/exception/DivisionByZeroException.java @@ -0,0 +1,9 @@ +package com.programmers.exception; + +public class DivisionByZeroException extends ArithmeticException { + + public DivisionByZeroException(String message) { + super(message); + } + +} diff --git a/app/src/main/java/com/programmers/exception/InvalidFormulaException.java b/app/src/main/java/com/programmers/exception/InvalidFormulaException.java new file mode 100644 index 000000000..f7cee22b8 --- /dev/null +++ b/app/src/main/java/com/programmers/exception/InvalidFormulaException.java @@ -0,0 +1,9 @@ +package com.programmers.exception; + +public class InvalidFormulaException extends NullPointerException { + + public InvalidFormulaException(String message) { + super(message); + } + +} diff --git a/app/src/main/java/com/programmers/exception/NotFoundMenuException.java b/app/src/main/java/com/programmers/exception/NotFoundMenuException.java new file mode 100644 index 000000000..56d1cc896 --- /dev/null +++ b/app/src/main/java/com/programmers/exception/NotFoundMenuException.java @@ -0,0 +1,9 @@ +package com.programmers.exception; + +public class NotFoundMenuException extends NullPointerException { + + public NotFoundMenuException(String message) { + super(message); + } + +} diff --git a/app/src/main/java/com/programmers/exception/NotFoundOperatorException.java b/app/src/main/java/com/programmers/exception/NotFoundOperatorException.java new file mode 100644 index 000000000..fb8cc9ae3 --- /dev/null +++ b/app/src/main/java/com/programmers/exception/NotFoundOperatorException.java @@ -0,0 +1,9 @@ +package com.programmers.exception; + +public class NotFoundOperatorException extends NullPointerException { + + public NotFoundOperatorException(String message) { + super(message); + } + +} diff --git a/app/src/main/java/com/programmers/exception/NotNumberException.java b/app/src/main/java/com/programmers/exception/NotNumberException.java new file mode 100644 index 000000000..ba3035fb1 --- /dev/null +++ b/app/src/main/java/com/programmers/exception/NotNumberException.java @@ -0,0 +1,9 @@ +package com.programmers.exception; + +public class NotNumberException extends NumberFormatException { + + public NotNumberException(String message) { + super(message); + } + +} From 0abe54e6fc059354c38a50cf7fcfd8071344396a Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:10:44 +0900 Subject: [PATCH 18/34] =?UTF-8?q?refactor=20:=20Operator=EB=A5=BC=20Parame?= =?UTF-8?q?terizedTest=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=B4=20=EC=97=AC?= =?UTF-8?q?=EB=9F=AC=20=EA=B0=9C=EB=A5=BC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=8F=20Calculator=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/programmers/calculator/Operator.java | 42 ------------- .../calculator/CalculatorTest.java | 16 +---- .../programmers/calculator/OperatorTest.java | 61 ------------------- .../com/programmers/util/OperatorTest.java | 58 ++++++++++++++++++ 4 files changed, 59 insertions(+), 118 deletions(-) delete mode 100644 app/src/main/java/com/programmers/calculator/Operator.java delete mode 100644 app/src/test/java/com/programmers/calculator/OperatorTest.java create mode 100644 app/src/test/java/com/programmers/util/OperatorTest.java diff --git a/app/src/main/java/com/programmers/calculator/Operator.java b/app/src/main/java/com/programmers/calculator/Operator.java deleted file mode 100644 index 82003dc09..000000000 --- a/app/src/main/java/com/programmers/calculator/Operator.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.programmers.calculator; - -import java.util.Arrays; -import java.util.function.BiFunction; - -public enum Operator { - - PLUS("+", (a, b) -> { return a + b; }), - MINUS("-", (a, b) -> { return a - b; }), - DIVIDE("/", (a, b) -> { - try { - return a / b; - } catch (ArithmeticException e) { - throw e; - } - }), - MUTIPLY("*", (a, b) -> { return a * b; }); - - private String operator; - private BiFunction func; - - Operator(String operator, BiFunction func) { - this.operator = operator; - this.func = func; - } - - public String getOperator() { - return operator; - } - - public BiFunction getFunc() { - return func; - } - - public static Operator of(String operator) { - return Arrays.stream(Operator.values()) - .filter(o -> o.getOperator().equals(operator)) - .findFirst() - .orElseThrow(NullPointerException::new); - } - -} diff --git a/app/src/test/java/com/programmers/calculator/CalculatorTest.java b/app/src/test/java/com/programmers/calculator/CalculatorTest.java index 159a7cdaa..09def043d 100644 --- a/app/src/test/java/com/programmers/calculator/CalculatorTest.java +++ b/app/src/test/java/com/programmers/calculator/CalculatorTest.java @@ -33,24 +33,10 @@ void calcPostfix() { List postfix = List.of("1", "2", "*", "4", "2", "/", "+"); // when - Integer answer = calculator.calcPostfix(postfix); + Integer answer = calculator.calculatePostfix(postfix); // then assertThat(answer).isEqualTo(4); } - @Test - @DisplayName("연산자 우선 순위 계산") - void isPriority() { - // given - String[] operator = { "+", "-", "*", "/" }; - int[] expectedPriority = { -1, -1, 1, 1 }; - - // when - for (int i = 0; i < 4; i++) { - int priority = calculator.getPriority(operator[i]); - assertThat(priority).isEqualTo(expectedPriority[i]); - } - } - } \ No newline at end of file diff --git a/app/src/test/java/com/programmers/calculator/OperatorTest.java b/app/src/test/java/com/programmers/calculator/OperatorTest.java deleted file mode 100644 index 637d1337c..000000000 --- a/app/src/test/java/com/programmers/calculator/OperatorTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.programmers.calculator; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; - -import java.util.function.BiFunction; - -import static org.assertj.core.api.Assertions.*; - -class OperatorTest { - - @Test - @DisplayName("연산자에 따라 제대로 계산") - void exactlyCalc() { - // given - Integer op1 = 6; Integer op2 = 2; - String[] operators = { "+", "-", "*", "/" }; - Integer[] results = { 8, 4, 12, 3 }; - - for (int i = 0; i < 4; i++) { - // when - Operator calc = Operator.of(operators[i]); - BiFunction func = calc.getFunc(); - - // then - assertThat(func.apply(op1, op2)) - .isEqualTo(results[i]); - } - } - - @Test - @DisplayName("이상한 연산자가 들어갈 경우 NullPointException 던짐") - void throwNullPointerExceptionWhenoddOperator() { - // given - String oddOperator = "!"; - - assertThatThrownBy(() -> { - // when - Operator.of(oddOperator); - // then - }).isExactlyInstanceOf(NullPointerException.class); - } - - @Test - @DisplayName("0으로 나누는 경우 ArithmeticException 던짐") - void throwWhenDivideZero() { - // given - Integer op1 = 4; Integer op2 = 0; - Operator calc = Operator.of("/"); - BiFunction func = calc.getFunc(); - - assertThatThrownBy(() -> { - // when - func.apply(op1, op2); - // then - }).isExactlyInstanceOf(ArithmeticException.class); - } - -} \ No newline at end of file diff --git a/app/src/test/java/com/programmers/util/OperatorTest.java b/app/src/test/java/com/programmers/util/OperatorTest.java new file mode 100644 index 000000000..9610317f1 --- /dev/null +++ b/app/src/test/java/com/programmers/util/OperatorTest.java @@ -0,0 +1,58 @@ +package com.programmers.util; + +import com.programmers.exception.DivisionByZeroException; +import com.programmers.exception.NotFoundOperatorException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.*; + +class OperatorTest { + + @ParameterizedTest + @DisplayName("연산자에 따라 제대로 계산") + @CsvSource(value={"+ 8", "- 4", "* 12", "/ 3"}, delimiter = ' ') + void exactlyCalc(String operator, Integer result) { + // given + Integer op1 = 6; Integer op2 = 2; + + // when + Operator calc = Operator.of(operator); + + // then + assertThat(calc.calculateOperation(op1, op2)) + .isEqualTo(result); + } + + @Test + @DisplayName("이상한 연산자가 들어갈 경우 NotFoundOperatorException 던짐") + void throwNullPointerExceptionWhenoddOperator() { + // given + String oddOperator = "!"; + + assertThatThrownBy(() -> { + // when + Operator.of(oddOperator); + // then + }).isExactlyInstanceOf(NotFoundOperatorException.class) + .hasMessage("찾을 수 없는 연산자입니다."); + } + + @Test + @DisplayName("0으로 나누는 경우 DivisionByZeroException 던짐") + void throwWhenDivideZero() { + // given + Integer op1 = 4; Integer op2 = 0; + Operator calc = Operator.of("/"); + + assertThatThrownBy(() -> { + // when + calc.calculateOperation(op1, op2); + // then + }).isExactlyInstanceOf(DivisionByZeroException.class) + .hasMessage("0으로 나눌 수 없습니다."); + } + +} \ No newline at end of file From fa9691b4a92bf059188a3e01183a6ab21af8605c Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:14:45 +0900 Subject: [PATCH 19/34] =?UTF-8?q?feat=20:=20=EB=8F=99=EC=9D=BC=ED=95=9C=20?= =?UTF-8?q?=EC=88=98=EC=8B=9D=EB=8F=84=20=EC=A0=80=EC=9E=A5=20=EB=B0=8F=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EC=88=9C=EC=9C=BC=EB=A1=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC=ED=95=9C=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=B0=98?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 저장 시간을 key로 사용 - 상태를 그대로 반환이 아닌 새로운 자료구조를 생성하여 반환 --- .../java/com/programmers/storage/Storage.java | 20 +++++++++---- .../com/programmers/storage/StorageTest.java | 28 +++++++++++-------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/programmers/storage/Storage.java b/app/src/main/java/com/programmers/storage/Storage.java index 7d2453dc6..c35219ffd 100644 --- a/app/src/main/java/com/programmers/storage/Storage.java +++ b/app/src/main/java/com/programmers/storage/Storage.java @@ -1,20 +1,28 @@ package com.programmers.storage; -import com.programmers.expression.Expression; +import com.programmers.util.Formula; +import java.time.LocalDateTime; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; public class Storage { - private final static Map map = new ConcurrentHashMap<>(); + private final static Map map = new ConcurrentHashMap<>(); - public void save(Expression expression, Integer result) { - map.put(expression.toString(), result); + public void save(Formula formula, Integer result) { + map.put(LocalDateTime.now(), formula.toString(result)); } - public Map findAll() { - return map; + public List findAll() { + if (map.size() == 0) return null; + return map.keySet().stream() + .sorted() + .map(date -> map.get(date)) + .collect(Collectors.toList()); + } } diff --git a/app/src/test/java/com/programmers/storage/StorageTest.java b/app/src/test/java/com/programmers/storage/StorageTest.java index b88b1870c..fb74a1872 100644 --- a/app/src/test/java/com/programmers/storage/StorageTest.java +++ b/app/src/test/java/com/programmers/storage/StorageTest.java @@ -1,11 +1,11 @@ package com.programmers.storage; -import com.programmers.expression.Expression; -import org.assertj.core.api.Assertions; +import com.programmers.util.Formula; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.Map; +import java.util.List; import static org.assertj.core.api.Assertions.*; @@ -13,21 +13,25 @@ class StorageTest { Storage storage = new Storage(); + @BeforeEach + void setup() throws InterruptedException { + storage.save(new Formula("1 * 2"), 2); + Thread.sleep(10); + storage.save(new Formula("2 / 2"), 1); + Thread.sleep(10); + storage.save(new Formula("1 * 2"), 2); + } + @Test - @DisplayName("저장을 한다") + @DisplayName("저장을 하고 중복 저장 및 날짜 순으로 조회") void save() { - // given - Expression expression = new Expression("1 * 2"); - int result = 3; - // when - storage.save(expression, result); - Map list = storage.findAll(); + List record = storage.findAll(); // then - assertThat(list) + assertThat(record) .isNotEmpty() - .containsExactly(entry("1 * 2", 3)); + .containsExactly("1 * 2 = 2", "2 / 2 = 1", "1 * 2 = 2"); } } \ No newline at end of file From 91ee3a94f7900e93b4bf934ccb3edbd3d69e7acc Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:17:20 +0900 Subject: [PATCH 20/34] =?UTF-8?q?feat=20:=20=EC=9E=90=EC=A3=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=90=98=EB=8A=94=20=EC=A0=95=EA=B7=9C=EC=8B=9D=20?= =?UTF-8?q?=ED=8C=A8=ED=84=B4=20=EB=AF=B8=EB=A6=AC=20=EC=BB=B4=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=ED=9B=84=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../programmers/expression/Expression.java | 30 --------- .../java/com/programmers/util/Formula.java | 35 +++++++++++ .../expression/ExpressionTest.java | 61 ------------------- .../com/programmers/util/FormulaTest.java | 58 ++++++++++++++++++ 4 files changed, 93 insertions(+), 91 deletions(-) delete mode 100644 app/src/main/java/com/programmers/expression/Expression.java create mode 100644 app/src/main/java/com/programmers/util/Formula.java delete mode 100644 app/src/test/java/com/programmers/expression/ExpressionTest.java create mode 100644 app/src/test/java/com/programmers/util/FormulaTest.java diff --git a/app/src/main/java/com/programmers/expression/Expression.java b/app/src/main/java/com/programmers/expression/Expression.java deleted file mode 100644 index df410d117..000000000 --- a/app/src/main/java/com/programmers/expression/Expression.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.programmers.expression; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public class Expression { - - private List expression; - - public Expression(String expression) { - isValid(expression); - this.expression = Arrays.stream(expression.split(" ")) - .collect(Collectors.toList()); - } - - public List getExpression() { - return expression; - } - - public void isValid(String expression) { - if (!expression.matches("([0-9] [+|-|*|/] )+[0-9]")) throw new IllegalArgumentException(); - } - - public String toString() { - return expression.stream() - .collect(Collectors.joining(" ")); - } - -} diff --git a/app/src/main/java/com/programmers/util/Formula.java b/app/src/main/java/com/programmers/util/Formula.java new file mode 100644 index 000000000..e5d5a24b3 --- /dev/null +++ b/app/src/main/java/com/programmers/util/Formula.java @@ -0,0 +1,35 @@ +package com.programmers.util; + +import com.programmers.exception.InvalidFormulaException; + +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class Formula { + + private final Pattern FORMULA_REGEX = Pattern.compile("([0-9] [+|-|*|/] )+[0-9]"); + private List formula; + + public Formula(String expression) { + isValid(expression); + this.formula = Arrays.stream(expression.split(" ")) + .collect(Collectors.toList()); + } + + public List getInfixFormula() { + return formula; + } + + public void isValid(String formula) { + if (!FORMULA_REGEX.matcher(formula).matches()) throw new InvalidFormulaException("유효하지 않은 수식 입력입니다."); + } + + public String toString(Integer result) { + String formulaToString = formula.stream() + .collect(Collectors.joining(" ")); + return formulaToString + " = " + result; + } + +} diff --git a/app/src/test/java/com/programmers/expression/ExpressionTest.java b/app/src/test/java/com/programmers/expression/ExpressionTest.java deleted file mode 100644 index 099f3bba7..000000000 --- a/app/src/test/java/com/programmers/expression/ExpressionTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.programmers.expression; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.*; - -class ExpressionTest { - - @Test - @DisplayName("문자열 연산을 리스트 연산으로 바꾸어준다.") - void changeStrExpressionToListExpression() { - // given - String strExpression = "3 * 4 / 2"; - - // when - Expression expression = new Expression(strExpression); - List listExpression = expression.getExpression(); - - // then - assertThat(listExpression) - .containsExactly("3", "*", "4", "/", "2"); - } - - @Test - @DisplayName("리스트 연산을 문자열 연산으로 변환한다.") - void changeListExpressionToStrExpression() { - // given - Expression expression = new Expression("3 * 4 / 2"); - - // when - String strExpression = expression.toString(); - - // then - assertThat(strExpression) - .isEqualTo("3 * 4 / 2"); - } - - @Test - @DisplayName("잘못된 입력은 예외를 던진다.") - void throwWhenInvalidInput() { - // given - String[] invalidInput = { - "1 + 1", - "1 + ", - " + 1", - " " - }; - - for (String s : invalidInput) { - assertThatThrownBy(() -> { - // when - Expression expression = new Expression(s); - // then - }).isExactlyInstanceOf(IllegalArgumentException.class); - } - } - -} \ No newline at end of file diff --git a/app/src/test/java/com/programmers/util/FormulaTest.java b/app/src/test/java/com/programmers/util/FormulaTest.java new file mode 100644 index 000000000..efb40ce1b --- /dev/null +++ b/app/src/test/java/com/programmers/util/FormulaTest.java @@ -0,0 +1,58 @@ +package com.programmers.util; + +import com.programmers.exception.InvalidFormulaException; +import com.programmers.util.Formula; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +class FormulaTest { + + @Test + @DisplayName("문자열 연산을 리스트 연산으로 바꾸어준다.") + void changeStrFormulaToListFormula() { + // given + String strExpression = "3 * 4 / 2"; + + // when + Formula formula = new Formula(strExpression); + List listExpression = formula.getInfixFormula(); + + // then + assertThat(listExpression) + .containsExactly("3", "*", "4", "/", "2"); + } + + @Test + @DisplayName("리스트 연산을 문자열 연산으로 변환한다.") + void changeListFormulaToStrFormula() { + // given + Formula formula = new Formula("3 * 4 / 2"); + Integer result = 6; + + // when + String strExpression = formula.toString(result); + + // then + assertThat(strExpression) + .isEqualTo("3 * 4 / 2 = 6"); + } + + @ParameterizedTest + @DisplayName("잘못된 입력은 예외를 던진다.") + @ValueSource(strings = {"1 + 1", "1 + ", "1 ! 1", " + 1", " ", "111 + 111"}) + void throwWhenInvalidInput(String invalidInput) { + assertThatThrownBy(() -> { + // when + Formula formula = new Formula(invalidInput); + // then + }).isExactlyInstanceOf(InvalidFormulaException.class) + .hasMessage("유효하지 않은 수식 입력입니다."); + } + +} \ No newline at end of file From a8161ac79c73956e1cf93cba39d0e2b867099688 Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:18:15 +0900 Subject: [PATCH 21/34] =?UTF-8?q?feat=20:=20=EB=A9=94=EB=89=B4=20enum?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 선택지에 대한 유효성 검사 --- .../main/java/com/programmers/util/Menu.java | 35 ++++++++++++++ .../java/com/programmers/util/MenuTest.java | 48 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 app/src/main/java/com/programmers/util/Menu.java create mode 100644 app/src/test/java/com/programmers/util/MenuTest.java diff --git a/app/src/main/java/com/programmers/util/Menu.java b/app/src/main/java/com/programmers/util/Menu.java new file mode 100644 index 000000000..911a4b875 --- /dev/null +++ b/app/src/main/java/com/programmers/util/Menu.java @@ -0,0 +1,35 @@ +package com.programmers.util; + +import com.programmers.exception.NotFoundMenuException; +import com.programmers.exception.NotNumberException; + +import java.util.Arrays; +import java.util.regex.Pattern; + +public enum Menu { + + VIEW(1), + CALCULATE(2), + EXIT(3); + + private final int select; + static final Pattern NUMBER = Pattern.compile("\\d+"); + + Menu(int select) { + this.select = select; + } + + public static Menu of(String select) { + isNumber(select); + int selectNum = Integer.parseInt(select); + return Arrays.stream(Menu.values()) + .filter(menu -> menu.select == selectNum) + .findFirst() + .orElseThrow(() -> new NotFoundMenuException("메뉴에서 없는 선택지입니다.")); + } + + private static void isNumber(String select) { + if (!NUMBER.matcher(select).matches()) throw new NotNumberException("선택지는 숫자만 입력할 수 있습니다."); + } + +} diff --git a/app/src/test/java/com/programmers/util/MenuTest.java b/app/src/test/java/com/programmers/util/MenuTest.java new file mode 100644 index 000000000..a0f7a3fc4 --- /dev/null +++ b/app/src/test/java/com/programmers/util/MenuTest.java @@ -0,0 +1,48 @@ +package com.programmers.util; + +import com.programmers.exception.NotFoundMenuException; +import com.programmers.exception.NotNumberException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.*; + +class MenuTest { + + @ParameterizedTest + @DisplayName("올바른 입력을 할 경우 해당되는 메뉴를 반환한다.") + @CsvSource(value = {"1 VIEW", "2 CALCULATE", "3 EXIT"}, delimiter = ' ') + void correctMenu(String select, Menu menu) { + assertThat(Menu.of(select)) + .isEqualTo(menu); + } + + @Test + @DisplayName("숫자가 아닌 입력이 들어오면 NotNumberException을 던진다.") + void throwNotNumberExceptionWhenNotNumber() { + // given + String select = "12W"; + + // then + assertThatThrownBy(() -> { + Menu.of(select); + }).isExactlyInstanceOf(NotNumberException.class) + .hasMessage("선택지는 숫자만 입력할 수 있습니다."); + } + + @Test + @DisplayName("선택지에 없는 숫자를 입력하면 NotFoundMenuException을 던진다.") + void throwNotFoundMenuException() { + // given + String select = "4"; + + // then + assertThatThrownBy(() -> { + Menu.of(select); + }).isExactlyInstanceOf(NotFoundMenuException.class) + .hasMessage("메뉴에서 없는 선택지입니다."); + } + +} \ No newline at end of file From 6b416776e11d4ec736891829c9f9f9e59b6137dd Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:19:12 +0900 Subject: [PATCH 22/34] =?UTF-8?q?feat=20:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/CalculatorService.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 app/src/main/java/com/programmers/service/CalculatorService.java diff --git a/app/src/main/java/com/programmers/service/CalculatorService.java b/app/src/main/java/com/programmers/service/CalculatorService.java new file mode 100644 index 000000000..7954d13bd --- /dev/null +++ b/app/src/main/java/com/programmers/service/CalculatorService.java @@ -0,0 +1,31 @@ +package com.programmers.service; + +import com.programmers.calculator.Calculator; +import com.programmers.storage.Storage; +import com.programmers.util.Formula; + +import java.util.List; + +public class CalculatorService { + + private final Calculator calculator; + private final Storage storage; + + public CalculatorService() { + this.calculator = new Calculator(); + this.storage = new Storage(); + } + + public Integer calculate(String stringOfFormula) { + Formula formula = new Formula(stringOfFormula); + List postfix = calculator.changeInfixToPostfix(formula.getInfixFormula()); + Integer result = calculator.calculatePostfix(postfix); + storage.save(formula, result); + return result; + } + + public List view() { + return storage.findAll(); + } + +} From f0aff99047855187bcc33a5eaac81756a5124336 Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:20:59 +0900 Subject: [PATCH 23/34] =?UTF-8?q?refactor=20:=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EB=A0=88=EC=9D=B4=EC=96=B4=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CalculatorController.java | 86 +++++++++---------- .../java/com/programmers/ui/InputView.java | 39 ++++++++- .../java/com/programmers/ui/OutputView.java | 35 +++----- 3 files changed, 88 insertions(+), 72 deletions(-) diff --git a/app/src/main/java/com/programmers/controller/CalculatorController.java b/app/src/main/java/com/programmers/controller/CalculatorController.java index 0be922e1d..4bf2690ef 100644 --- a/app/src/main/java/com/programmers/controller/CalculatorController.java +++ b/app/src/main/java/com/programmers/controller/CalculatorController.java @@ -1,70 +1,64 @@ package com.programmers.controller; -import com.programmers.calculator.Calculator; -import com.programmers.expression.Expression; -import com.programmers.storage.Storage; +import com.programmers.service.CalculatorService; +import com.programmers.util.Formula; import com.programmers.ui.InputView; import com.programmers.ui.OutputView; +import com.programmers.util.Menu; -import java.io.BufferedReader; -import java.io.EOFException; import java.io.IOException; -import java.io.InputStreamReader; import java.util.List; -import java.util.Map; public class CalculatorController { - private InputView inputView = new InputView(); - private OutputView outputView = new OutputView(); - private Calculator calculator = new Calculator(); - private Storage storage = new Storage(); + private final InputView inputView; + private final OutputView outputView; + private final CalculatorService calculatorService; + + public CalculatorController() { + this.inputView = new InputView(); + this.outputView = new OutputView(); + this.calculatorService = new CalculatorService(); + } - public void run() { - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - while (true) { + public void run() { + while (true) { + try { outputView.init(); - String select = inputView.select(br); - if (!isValidInput(select)) continue; - Integer num = Integer.parseInt(select); - if (num.equals(1)) view(); - else if (num.equals(2)) calculate(br); - else { - outputView.inputInOneAndTwo(); - continue; + String select = inputView.select(); + Menu menu = Menu.of(select); + if (menu == Menu.VIEW) view(); + else if (menu == Menu.CALCULATE) calculate(); + else if (menu == Menu.EXIT) { + exit(); + break; } + } catch(Exception e){ + outputView.printExceptionMessage(e.getMessage()); + if (e instanceof IOException) break; } - } catch (IOException e) { - outputView.eof(); + } + + try { + inputView.close(); + } catch (Exception e) { + outputView.printExceptionMessage(e.getMessage()); } } - private boolean isValidInput(String select) throws IOException { - if (select.isEmpty()) throw new IOException(); - if (!select.matches("[0-9]+")){ - outputView.inputIsOnlyNumber(); - return false; - } return true; + private void calculate() { + String formula = inputView.formula(); + Integer result = calculatorService.calculate(formula); + outputView.viewResult(result); } - private void calculate(BufferedReader br) throws IOException { - try { - String str = inputView.expression(br); - Expression expression = new Expression(str); - List postfix = calculator.changeInfixToPostfix(expression.getExpression()); - Integer result = calculator.calcPostfix(postfix); - storage.save(expression, result); - outputView.viewResult(result); - } catch (IllegalArgumentException e) { - outputView.invalidInputException(); - } catch (ArithmeticException e) { - outputView.divideByZeroException(); - } + private void view() { + List record = calculatorService.view(); + outputView.viewRecord(record); } - private void view() { - Map list = storage.findAll(); - outputView.viewList(list); + private void exit() { + outputView.exit(); } } diff --git a/app/src/main/java/com/programmers/ui/InputView.java b/app/src/main/java/com/programmers/ui/InputView.java index 0d697d8a6..c1a59ca72 100644 --- a/app/src/main/java/com/programmers/ui/InputView.java +++ b/app/src/main/java/com/programmers/ui/InputView.java @@ -1,16 +1,47 @@ package com.programmers.ui; +import com.programmers.exception.AbnormalTerminationException; + import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; public class InputView { - public String select(BufferedReader br) throws IOException { - return br.readLine(); + private final BufferedReader br; + + public InputView() { + br = new BufferedReader(new InputStreamReader(System.in)); + } + + public String select() { + try { + return br.readLine(); + } catch (IOException e) { + throwAbnormalTerminationException(); + } + return null; } - public String expression(BufferedReader br) throws IOException { - return br.readLine(); + public String formula() { + try { + return br.readLine(); + } catch (IOException e) { + throwAbnormalTerminationException(); + } + return null; + } + + public void close() { + try { + br.close(); + } catch (IOException e) { + throwAbnormalTerminationException(); + } + } + + private AbnormalTerminationException throwAbnormalTerminationException() { + return new AbnormalTerminationException("입력에 예외가 발생하여 비정상적으로 종료되었습니다."); } } diff --git a/app/src/main/java/com/programmers/ui/OutputView.java b/app/src/main/java/com/programmers/ui/OutputView.java index 8dcaf2694..979514513 100644 --- a/app/src/main/java/com/programmers/ui/OutputView.java +++ b/app/src/main/java/com/programmers/ui/OutputView.java @@ -1,43 +1,34 @@ package com.programmers.ui; -import java.util.Map; +import java.util.List; public class OutputView { public void init() { System.out.println("1. 조회"); System.out.println("2. 계산"); + System.out.println("3. 종료"); + System.out.print("\n선택 : "); } public void viewResult(Integer result) { - System.out.println(result); + System.out.println(result + "\n"); } - public void viewList(Map list) { - for (String expression : list.keySet()) { - Integer result = list.get(expression); - System.out.println(expression + " = " + result); + public void viewRecord(List record) { + System.out.print("\n"); + if (record != null) { + record.stream().forEach(System.out::println); + System.out.print("\n"); } } - public void eof() { - System.out.println("프로그램을 종료합니다."); + public void exit() { + System.out.println("\n프로그램을 종료합니다."); } - public void inputInOneAndTwo() { - System.out.println("입력은 1과 2만 가능합니다."); - } - - public void inputIsOnlyNumber() { - System.out.println("입력은 오직 숫자만 가능합니다."); - } - - public void divideByZeroException() { - System.out.println("0으로 나눌 수 없습니다."); - } - - public void invalidInputException() { - System.out.println("잘못된 입력입니다."); + public void printExceptionMessage(String message) { + System.out.println(message); } } From 5e74365e1edf49a0d548ad6db7516593bc4117e5 Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:21:45 +0900 Subject: [PATCH 24/34] =?UTF-8?q?refactor=20:=20=EC=95=A0=ED=94=8C?= =?UTF-8?q?=EB=A6=AC=EC=BC=80=EC=9D=B4=EC=85=98=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{App.java => CalculatorApplication.java} | 2 +- app/src/test/java/com/programmers/AppTest.java | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) rename app/src/main/java/com/programmers/{App.java => CalculatorApplication.java} (89%) delete mode 100644 app/src/test/java/com/programmers/AppTest.java diff --git a/app/src/main/java/com/programmers/App.java b/app/src/main/java/com/programmers/CalculatorApplication.java similarity index 89% rename from app/src/main/java/com/programmers/App.java rename to app/src/main/java/com/programmers/CalculatorApplication.java index 2462201cc..6b5e760e4 100644 --- a/app/src/main/java/com/programmers/App.java +++ b/app/src/main/java/com/programmers/CalculatorApplication.java @@ -5,7 +5,7 @@ import com.programmers.controller.CalculatorController; -public class App { +public class CalculatorApplication { public static void main(String[] args) { CalculatorController calculatorController = new CalculatorController(); diff --git a/app/src/test/java/com/programmers/AppTest.java b/app/src/test/java/com/programmers/AppTest.java deleted file mode 100644 index 166d15564..000000000 --- a/app/src/test/java/com/programmers/AppTest.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This Java source file was generated by the Gradle 'init' task. - */ -package com.programmers; - -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -class AppTest { - @Test void appHasAGreeting() { - App classUnderTest = new App(); - assertNotNull(classUnderTest.getGreeting(), "app should have a greeting"); - } -} From 752d38d2334f4a9f6328ee114ca54e8e13cbd1eb Mon Sep 17 00:00:00 2001 From: heenahan Date: Thu, 15 Jun 2023 15:58:00 +0900 Subject: [PATCH 25/34] =?UTF-8?q?chore=20:=20import=EB=AC=B8=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/programmers/calculator/Calculator.java | 5 ++++- .../com/programmers/controller/CalculatorController.java | 1 - app/src/test/java/com/programmers/util/FormulaTest.java | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/programmers/calculator/Calculator.java b/app/src/main/java/com/programmers/calculator/Calculator.java index f4ffef450..f232639e5 100644 --- a/app/src/main/java/com/programmers/calculator/Calculator.java +++ b/app/src/main/java/com/programmers/calculator/Calculator.java @@ -2,7 +2,10 @@ import com.programmers.util.Operator; -import java.util.*; +import java.util.List; +import java.util.ArrayList; +import java.util.Deque; +import java.util.ArrayDeque; import java.util.regex.Pattern; public class Calculator { diff --git a/app/src/main/java/com/programmers/controller/CalculatorController.java b/app/src/main/java/com/programmers/controller/CalculatorController.java index 4bf2690ef..a42a58065 100644 --- a/app/src/main/java/com/programmers/controller/CalculatorController.java +++ b/app/src/main/java/com/programmers/controller/CalculatorController.java @@ -1,7 +1,6 @@ package com.programmers.controller; import com.programmers.service.CalculatorService; -import com.programmers.util.Formula; import com.programmers.ui.InputView; import com.programmers.ui.OutputView; import com.programmers.util.Menu; diff --git a/app/src/test/java/com/programmers/util/FormulaTest.java b/app/src/test/java/com/programmers/util/FormulaTest.java index efb40ce1b..e691eea5e 100644 --- a/app/src/test/java/com/programmers/util/FormulaTest.java +++ b/app/src/test/java/com/programmers/util/FormulaTest.java @@ -1,7 +1,6 @@ package com.programmers.util; import com.programmers.exception.InvalidFormulaException; -import com.programmers.util.Formula; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; From d2e0f24b31f2e297cafe1512708fa278ad97ee60 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 17 Jun 2023 23:10:38 +0900 Subject: [PATCH 26/34] =?UTF-8?q?refactor=20:=20=ED=9B=84=EC=9C=84=20?= =?UTF-8?q?=ED=91=9C=ED=98=84=EC=8B=9D=20=EB=B3=80=ED=99=98=EA=B3=BC=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../programmers/calculator/Calculator.java | 63 +++---------------- .../calculator/PostfixCalculator.java | 38 +++++++++++ .../calculator/PostfixConversion.java | 49 +++++++++++++++ 3 files changed, 95 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/com/programmers/calculator/PostfixCalculator.java create mode 100644 app/src/main/java/com/programmers/calculator/PostfixConversion.java diff --git a/app/src/main/java/com/programmers/calculator/Calculator.java b/app/src/main/java/com/programmers/calculator/Calculator.java index f232639e5..0c977912e 100644 --- a/app/src/main/java/com/programmers/calculator/Calculator.java +++ b/app/src/main/java/com/programmers/calculator/Calculator.java @@ -1,67 +1,20 @@ package com.programmers.calculator; -import com.programmers.util.Operator; - import java.util.List; -import java.util.ArrayList; -import java.util.Deque; -import java.util.ArrayDeque; -import java.util.regex.Pattern; public class Calculator { - private final Pattern NUMBER = Pattern.compile("\\d+"); + private final PostfixConversion postfixConversion; + private final PostfixCalculator postfixCalculator; - public List changeInfixToPostfix(List infix) { - List postfix = new ArrayList<>(); - Deque deque = new ArrayDeque<>(); - - infix.stream() - .forEach(s -> { - if (NUMBER.matcher(s).matches()) { // 숫자일 경우 - postfix.add(s); - } else { // 숫자 아닐 경우 - Operator operator = Operator.of(s); - int priority = operator.getPriority(); - // 덱이 비었거나 - while (!deque.isEmpty()) { - Operator topOperator = Operator.of(deque.peekLast()); - int topPriority = topOperator.getPriority(); - - // top의 우선 순위가 높거나 같을 경우 - if (topPriority >= priority) postfix.add(deque.pollLast()); - // top의 우선 순위가 낮을 경우 - else break; - } - deque.addLast(s); // 연산자 넣음 - } - }); - - // 스택에 남아있는 연산자 모두 집어 넣음 - while (!deque.isEmpty()) postfix.add(deque.pollLast()); - - return postfix; + public Calculator() { + postfixConversion = new PostfixConversion(); + postfixCalculator = new PostfixCalculator(); } - public Integer calculatePostfix(List postfix) { - Deque deque = new ArrayDeque<>(); - - postfix.stream() - .forEach(s -> { - // 숫자일 경우 덱에 넣음 - if (NUMBER.matcher(s).matches()) deque.addLast(Integer.parseInt(s)); - else { // 연산자 일 경우 - Integer op1 = deque.pollLast(); - Integer op2 = deque.pollLast(); - - Operator calc = Operator.of(s); - Integer result = calc.calculateOperation(op2, op1); - - deque.addLast(result); - } - }); - - return deque.pollLast(); + public Integer calculate(List infix) { + List postfix = postfixConversion.changeInfixToPostfix(infix); + return postfixCalculator.calculatePostfix(postfix); } } diff --git a/app/src/main/java/com/programmers/calculator/PostfixCalculator.java b/app/src/main/java/com/programmers/calculator/PostfixCalculator.java new file mode 100644 index 000000000..6c7c44bc5 --- /dev/null +++ b/app/src/main/java/com/programmers/calculator/PostfixCalculator.java @@ -0,0 +1,38 @@ +package com.programmers.calculator; + +import com.programmers.util.Operator; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.regex.Pattern; + +public class PostfixCalculator { + + private static final Pattern NUMBER = Pattern.compile("\\d+"); + + public Integer calculatePostfix(List postfix) { + Deque deque = new ArrayDeque<>(); + + postfix.stream() + .forEach(s -> { calculatePostfixWithDeque(s, deque); }); + + return deque.pollLast(); + } + + private void calculatePostfixWithDeque(String s, Deque deque) { + if (NUMBER.matcher(s).matches()) { + deque.addLast(Integer.parseInt(s)); + return; + } + // 연산자 일 경우 + Integer op1 = deque.pollLast(); + Integer op2 = deque.pollLast(); + + Operator calc = Operator.of(s); + Integer result = calc.calculateOperation(op2, op1); + + deque.addLast(result); + } + +} diff --git a/app/src/main/java/com/programmers/calculator/PostfixConversion.java b/app/src/main/java/com/programmers/calculator/PostfixConversion.java new file mode 100644 index 000000000..7d0d48262 --- /dev/null +++ b/app/src/main/java/com/programmers/calculator/PostfixConversion.java @@ -0,0 +1,49 @@ +package com.programmers.calculator; + +import com.programmers.util.Operator; + +import java.util.List; +import java.util.ArrayList; +import java.util.Deque; +import java.util.ArrayDeque; +import java.util.regex.Pattern; + +public class PostfixConversion { + + private static final Pattern NUMBER = Pattern.compile("\\d+"); + + public List changeInfixToPostfix(List infix) { + List postfix = new ArrayList<>(); + Deque deque = new ArrayDeque<>(); + + infix.stream() + .forEach(s -> { makePostfixWithDeque(s, postfix, deque); }); + + // 스택에 남아있는 연산자 모두 집어 넣음 + while (!deque.isEmpty()) postfix.add(deque.pollLast()); + + return postfix; + } + + private void makePostfixWithDeque(String s, List postfix, Deque deque) { + if (NUMBER.matcher(s).matches()) { // 숫자일 경우 + postfix.add(s); + return; + } + // 숫자 아닐 경우 + Operator operator = Operator.of(s); + int priority = operator.getPriority(); + // 덱이 비었거나 + while (!deque.isEmpty()) { + Operator topOperator = Operator.of(deque.peekLast()); + int topPriority = topOperator.getPriority(); + + // top의 우선 순위가 높거나 같을 경우 + if (topPriority >= priority) postfix.add(deque.pollLast()); + // top의 우선 순위가 낮을 경우 + else break; + } + deque.addLast(s); // 연산자 넣음 + } + +} From 26995f4d4861fac3faab68a33a3cf00c9cbe8450 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 17 Jun 2023 23:15:29 +0900 Subject: [PATCH 27/34] =?UTF-8?q?refactor=20:=20Formula=EA=B0=80=20?= =?UTF-8?q?=EC=8A=A4=EC=8A=A4=EB=A1=9C=20=EA=B3=84=EC=82=B0=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/programmers/calculator/Formula.java | 44 +++++++++++++++++++ .../java/com/programmers/util/Formula.java | 35 --------------- 2 files changed, 44 insertions(+), 35 deletions(-) create mode 100644 app/src/main/java/com/programmers/calculator/Formula.java delete mode 100644 app/src/main/java/com/programmers/util/Formula.java diff --git a/app/src/main/java/com/programmers/calculator/Formula.java b/app/src/main/java/com/programmers/calculator/Formula.java new file mode 100644 index 000000000..e9c76f73c --- /dev/null +++ b/app/src/main/java/com/programmers/calculator/Formula.java @@ -0,0 +1,44 @@ +package com.programmers.calculator; + +import com.programmers.exception.InvalidFormulaException; + +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class Formula { + + private static final Pattern FORMULA_REGEX = Pattern.compile("([0-9] [+|-|*|/] )+[0-9]"); + private static final String EQUAL = " = "; + + private final Calculator calculator; + + private String formula; + private Integer result; + + public Formula(String formula) { + isValid(formula); + this.formula = formula; + this.calculator = new Calculator(); + } + + public List getInfixListFormula() { + return Arrays.stream(formula.split(" ")) + .collect(Collectors.toList()); + } + + public void isValid(String formula) { + if (!FORMULA_REGEX.matcher(formula).matches()) throw new InvalidFormulaException("유효하지 않은 수식 입력입니다."); + } + + public Integer calcualteFormula() { + result = calculator.calculate(getInfixListFormula()); + return result; + } + + public String toString() { + return formula + EQUAL + result; + } + +} diff --git a/app/src/main/java/com/programmers/util/Formula.java b/app/src/main/java/com/programmers/util/Formula.java deleted file mode 100644 index e5d5a24b3..000000000 --- a/app/src/main/java/com/programmers/util/Formula.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.programmers.util; - -import com.programmers.exception.InvalidFormulaException; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -public class Formula { - - private final Pattern FORMULA_REGEX = Pattern.compile("([0-9] [+|-|*|/] )+[0-9]"); - private List formula; - - public Formula(String expression) { - isValid(expression); - this.formula = Arrays.stream(expression.split(" ")) - .collect(Collectors.toList()); - } - - public List getInfixFormula() { - return formula; - } - - public void isValid(String formula) { - if (!FORMULA_REGEX.matcher(formula).matches()) throw new InvalidFormulaException("유효하지 않은 수식 입력입니다."); - } - - public String toString(Integer result) { - String formulaToString = formula.stream() - .collect(Collectors.joining(" ")); - return formulaToString + " = " + result; - } - -} From 8984cd5264b3da8b1d75f57524b519a7f771b9f7 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 17 Jun 2023 23:21:04 +0900 Subject: [PATCH 28/34] =?UTF-8?q?feat=20:=20=EC=A0=80=EC=9E=A5=EC=86=8C=20?= =?UTF-8?q?List=EB=A1=9C=20=EC=9E=90=EB=A3=8C=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/programmers/storage/Storage.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/programmers/storage/Storage.java b/app/src/main/java/com/programmers/storage/Storage.java index c35219ffd..8a4f39d9e 100644 --- a/app/src/main/java/com/programmers/storage/Storage.java +++ b/app/src/main/java/com/programmers/storage/Storage.java @@ -1,28 +1,26 @@ package com.programmers.storage; -import com.programmers.util.Formula; +import com.programmers.calculator.Formula; -import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class Storage { - private final static Map map = new ConcurrentHashMap<>(); + private final static List list = new ArrayList<>(); - public void save(Formula formula, Integer result) { - map.put(LocalDateTime.now(), formula.toString(result)); + public void save(Formula formula) { + list.add(formula); } public List findAll() { - if (map.size() == 0) return null; - return map.keySet().stream() - .sorted() - .map(date -> map.get(date)) - .collect(Collectors.toList()); - + if (list.size() == 0) { + return null; + } + return list.stream() + .map(Formula::toString) + .collect(Collectors.toList()); } } From 6ce753c648929ed6dcf4a42e7601becf648fe16d Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 17 Jun 2023 23:26:19 +0900 Subject: [PATCH 29/34] =?UTF-8?q?refactor=20:=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EA=B3=BC=20=EA=B3=84=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/PostfixCalculatorTest.java | 28 +++++++++++++++++++ ...orTest.java => PostfixConversionTest.java} | 19 ++----------- .../com/programmers/storage/StorageTest.java | 22 +++++++++------ .../com/programmers/util/FormulaTest.java | 11 ++++---- 4 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 app/src/test/java/com/programmers/calculator/PostfixCalculatorTest.java rename app/src/test/java/com/programmers/calculator/{CalculatorTest.java => PostfixConversionTest.java} (55%) diff --git a/app/src/test/java/com/programmers/calculator/PostfixCalculatorTest.java b/app/src/test/java/com/programmers/calculator/PostfixCalculatorTest.java new file mode 100644 index 000000000..ed2922961 --- /dev/null +++ b/app/src/test/java/com/programmers/calculator/PostfixCalculatorTest.java @@ -0,0 +1,28 @@ +package com.programmers.calculator; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class PostfixCalculatorTest { + + PostfixCalculator postfixCalculator = new PostfixCalculator(); + + @Test + @DisplayName("후위 표기식을 계산") + void calcPostfix() { + // given + List postfix = List.of("1", "2", "*", "4", "2", "/", "+"); + + // when + Integer answer = postfixCalculator.calculatePostfix(postfix); + + // then + assertThat(answer).isEqualTo(4); + } + + +} \ No newline at end of file diff --git a/app/src/test/java/com/programmers/calculator/CalculatorTest.java b/app/src/test/java/com/programmers/calculator/PostfixConversionTest.java similarity index 55% rename from app/src/test/java/com/programmers/calculator/CalculatorTest.java rename to app/src/test/java/com/programmers/calculator/PostfixConversionTest.java index 09def043d..1d0454afd 100644 --- a/app/src/test/java/com/programmers/calculator/CalculatorTest.java +++ b/app/src/test/java/com/programmers/calculator/PostfixConversionTest.java @@ -7,9 +7,9 @@ import static org.assertj.core.api.Assertions.*; -class CalculatorTest { +class PostfixConversionTest { - Calculator calculator = new Calculator(); + PostfixConversion postfixConversion = new PostfixConversion(); @Test @DisplayName("중위 표기식을 후위 표기식으로 변환") @@ -18,7 +18,7 @@ void infixTopostfix() { List infix1 = List.of("1", "*", "2", "+", "3", "/", "4"); // when - List postfix = calculator.changeInfixToPostfix(infix1); + List postfix = postfixConversion.changeInfixToPostfix(infix1); // then assertThat(postfix) @@ -26,17 +26,4 @@ void infixTopostfix() { .containsExactly("1", "2", "*", "3", "4", "/", "+"); } - @Test - @DisplayName("후위 표기식을 계산") - void calcPostfix() { - // given - List postfix = List.of("1", "2", "*", "4", "2", "/", "+"); - - // when - Integer answer = calculator.calculatePostfix(postfix); - - // then - assertThat(answer).isEqualTo(4); - } - } \ No newline at end of file diff --git a/app/src/test/java/com/programmers/storage/StorageTest.java b/app/src/test/java/com/programmers/storage/StorageTest.java index fb74a1872..43ba2ec3b 100644 --- a/app/src/test/java/com/programmers/storage/StorageTest.java +++ b/app/src/test/java/com/programmers/storage/StorageTest.java @@ -1,6 +1,6 @@ package com.programmers.storage; -import com.programmers.util.Formula; +import com.programmers.calculator.Formula; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -14,16 +14,22 @@ class StorageTest { Storage storage = new Storage(); @BeforeEach - void setup() throws InterruptedException { - storage.save(new Formula("1 * 2"), 2); - Thread.sleep(10); - storage.save(new Formula("2 / 2"), 1); - Thread.sleep(10); - storage.save(new Formula("1 * 2"), 2); + void setup() { + Formula formula1 = new Formula("1 * 2"); + formula1.calcualteFormula(); + storage.save(formula1); + + Formula formula2 = new Formula("2 / 2"); + formula2.calcualteFormula(); + storage.save(formula2); + + Formula formula3 = new Formula("1 * 2"); + formula3.calcualteFormula(); + storage.save(formula3); } @Test - @DisplayName("저장을 하고 중복 저장 및 날짜 순으로 조회") + @DisplayName("저장을 한다.") void save() { // when List record = storage.findAll(); diff --git a/app/src/test/java/com/programmers/util/FormulaTest.java b/app/src/test/java/com/programmers/util/FormulaTest.java index e691eea5e..34a5016d4 100644 --- a/app/src/test/java/com/programmers/util/FormulaTest.java +++ b/app/src/test/java/com/programmers/util/FormulaTest.java @@ -1,5 +1,6 @@ package com.programmers.util; +import com.programmers.calculator.Formula; import com.programmers.exception.InvalidFormulaException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -20,7 +21,7 @@ void changeStrFormulaToListFormula() { // when Formula formula = new Formula(strExpression); - List listExpression = formula.getInfixFormula(); + List listExpression = formula.getInfixListFormula(); // then assertThat(listExpression) @@ -28,17 +29,17 @@ void changeStrFormulaToListFormula() { } @Test - @DisplayName("리스트 연산을 문자열 연산으로 변환한다.") + @DisplayName("수식을 계산한 결과와 함께 문자열로 만든다.") void changeListFormulaToStrFormula() { // given Formula formula = new Formula("3 * 4 / 2"); - Integer result = 6; + Integer result = formula.calcualteFormula(); // when - String strExpression = formula.toString(result); + String formulaOfString = formula.toString(); // then - assertThat(strExpression) + assertThat(formulaOfString) .isEqualTo("3 * 4 / 2 = 6"); } From 3a2acbf1a8813ecc5439455cee8d70c4486b3251 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 17 Jun 2023 23:27:45 +0900 Subject: [PATCH 30/34] =?UTF-8?q?refactor=20:=20=EB=A9=94=EB=89=B4=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20String=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/NotNumberException.java | 9 -------- .../main/java/com/programmers/util/Menu.java | 21 ++++++------------- .../java/com/programmers/util/MenuTest.java | 14 ------------- 3 files changed, 6 insertions(+), 38 deletions(-) delete mode 100644 app/src/main/java/com/programmers/exception/NotNumberException.java diff --git a/app/src/main/java/com/programmers/exception/NotNumberException.java b/app/src/main/java/com/programmers/exception/NotNumberException.java deleted file mode 100644 index ba3035fb1..000000000 --- a/app/src/main/java/com/programmers/exception/NotNumberException.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.programmers.exception; - -public class NotNumberException extends NumberFormatException { - - public NotNumberException(String message) { - super(message); - } - -} diff --git a/app/src/main/java/com/programmers/util/Menu.java b/app/src/main/java/com/programmers/util/Menu.java index 911a4b875..c5432bdf4 100644 --- a/app/src/main/java/com/programmers/util/Menu.java +++ b/app/src/main/java/com/programmers/util/Menu.java @@ -1,35 +1,26 @@ package com.programmers.util; import com.programmers.exception.NotFoundMenuException; -import com.programmers.exception.NotNumberException; import java.util.Arrays; -import java.util.regex.Pattern; public enum Menu { - VIEW(1), - CALCULATE(2), - EXIT(3); + VIEW("1"), + CALCULATE("2"), + EXIT("3"); - private final int select; - static final Pattern NUMBER = Pattern.compile("\\d+"); + private final String select; - Menu(int select) { + Menu(String select) { this.select = select; } public static Menu of(String select) { - isNumber(select); - int selectNum = Integer.parseInt(select); return Arrays.stream(Menu.values()) - .filter(menu -> menu.select == selectNum) + .filter(menu -> menu.select.equals(select)) .findFirst() .orElseThrow(() -> new NotFoundMenuException("메뉴에서 없는 선택지입니다.")); } - private static void isNumber(String select) { - if (!NUMBER.matcher(select).matches()) throw new NotNumberException("선택지는 숫자만 입력할 수 있습니다."); - } - } diff --git a/app/src/test/java/com/programmers/util/MenuTest.java b/app/src/test/java/com/programmers/util/MenuTest.java index a0f7a3fc4..0a8eb3d06 100644 --- a/app/src/test/java/com/programmers/util/MenuTest.java +++ b/app/src/test/java/com/programmers/util/MenuTest.java @@ -1,7 +1,6 @@ package com.programmers.util; import com.programmers.exception.NotFoundMenuException; -import com.programmers.exception.NotNumberException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -19,19 +18,6 @@ void correctMenu(String select, Menu menu) { .isEqualTo(menu); } - @Test - @DisplayName("숫자가 아닌 입력이 들어오면 NotNumberException을 던진다.") - void throwNotNumberExceptionWhenNotNumber() { - // given - String select = "12W"; - - // then - assertThatThrownBy(() -> { - Menu.of(select); - }).isExactlyInstanceOf(NotNumberException.class) - .hasMessage("선택지는 숫자만 입력할 수 있습니다."); - } - @Test @DisplayName("선택지에 없는 숫자를 입력하면 NotFoundMenuException을 던진다.") void throwNotFoundMenuException() { From 8ec3a90c13d026c3f7498fd22e6744e8a58285d6 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 17 Jun 2023 23:28:25 +0900 Subject: [PATCH 31/34] =?UTF-8?q?refactor=20:=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EB=A0=88=EC=9D=B4=EC=96=B4=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/programmers/service/CalculatorService.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/programmers/service/CalculatorService.java b/app/src/main/java/com/programmers/service/CalculatorService.java index 7954d13bd..11523af8e 100644 --- a/app/src/main/java/com/programmers/service/CalculatorService.java +++ b/app/src/main/java/com/programmers/service/CalculatorService.java @@ -1,26 +1,22 @@ package com.programmers.service; -import com.programmers.calculator.Calculator; import com.programmers.storage.Storage; -import com.programmers.util.Formula; +import com.programmers.calculator.Formula; import java.util.List; public class CalculatorService { - private final Calculator calculator; private final Storage storage; public CalculatorService() { - this.calculator = new Calculator(); this.storage = new Storage(); } public Integer calculate(String stringOfFormula) { Formula formula = new Formula(stringOfFormula); - List postfix = calculator.changeInfixToPostfix(formula.getInfixFormula()); - Integer result = calculator.calculatePostfix(postfix); - storage.save(formula, result); + Integer result = formula.calcualteFormula(); + storage.save(formula); return result; } From d59e1c035afe66a5175b93a36d6b6e06f6e77b8f Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 17 Jun 2023 23:28:47 +0900 Subject: [PATCH 32/34] =?UTF-8?q?refactor=20:=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EB=A0=88=EC=9D=B4=EC=96=B4=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/programmers/controller/CalculatorController.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/programmers/controller/CalculatorController.java b/app/src/main/java/com/programmers/controller/CalculatorController.java index a42a58065..7fbd01b00 100644 --- a/app/src/main/java/com/programmers/controller/CalculatorController.java +++ b/app/src/main/java/com/programmers/controller/CalculatorController.java @@ -26,9 +26,11 @@ public void run() { outputView.init(); String select = inputView.select(); Menu menu = Menu.of(select); - if (menu == Menu.VIEW) view(); - else if (menu == Menu.CALCULATE) calculate(); - else if (menu == Menu.EXIT) { + if (menu == Menu.VIEW) { + view(); + } else if (menu == Menu.CALCULATE) { + calculate(); + } else if (menu == Menu.EXIT) { exit(); break; } From b813f7c53410e2b081b176647370693c85f21573 Mon Sep 17 00:00:00 2001 From: heenahan Date: Sat, 17 Jun 2023 23:31:39 +0900 Subject: [PATCH 33/34] =?UTF-8?q?fix=20:=20=EB=A7=88=EC=9D=B4=EB=84=88?= =?UTF-8?q?=EC=8A=A4=20=EB=B6=80=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=EC=8B=9C?= =?UTF-8?q?=20=EC=9C=A0=ED=9A=A8=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/programmers/calculator/Formula.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/programmers/calculator/Formula.java b/app/src/main/java/com/programmers/calculator/Formula.java index e9c76f73c..b02a1aa71 100644 --- a/app/src/main/java/com/programmers/calculator/Formula.java +++ b/app/src/main/java/com/programmers/calculator/Formula.java @@ -9,7 +9,7 @@ public class Formula { - private static final Pattern FORMULA_REGEX = Pattern.compile("([0-9] [+|-|*|/] )+[0-9]"); + private static final Pattern FORMULA_REGEX = Pattern.compile("([0-9] [+|\\-|*|/] )+[0-9]"); private static final String EQUAL = " = "; private final Calculator calculator; From f781b5f893122c540a4dfa4cbf5c5ab649b9dd55 Mon Sep 17 00:00:00 2001 From: heenahan Date: Tue, 20 Jun 2023 01:42:09 +0900 Subject: [PATCH 34/34] =?UTF-8?q?refactor=20:=EC=9D=B8=EC=9E=90=EB=A1=9C?= =?UTF-8?q?=20Formula=EB=A5=BC=20=EB=B0=9B=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/programmers/calculator/Calculator.java | 4 ++-- app/src/main/java/com/programmers/calculator/Formula.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/programmers/calculator/Calculator.java b/app/src/main/java/com/programmers/calculator/Calculator.java index 0c977912e..369a2148a 100644 --- a/app/src/main/java/com/programmers/calculator/Calculator.java +++ b/app/src/main/java/com/programmers/calculator/Calculator.java @@ -12,8 +12,8 @@ public Calculator() { postfixCalculator = new PostfixCalculator(); } - public Integer calculate(List infix) { - List postfix = postfixConversion.changeInfixToPostfix(infix); + public Integer calculate(Formula formula) { + List postfix = postfixConversion.changeInfixToPostfix(formula.getInfixListFormula()); return postfixCalculator.calculatePostfix(postfix); } diff --git a/app/src/main/java/com/programmers/calculator/Formula.java b/app/src/main/java/com/programmers/calculator/Formula.java index b02a1aa71..40b4aa55a 100644 --- a/app/src/main/java/com/programmers/calculator/Formula.java +++ b/app/src/main/java/com/programmers/calculator/Formula.java @@ -33,7 +33,7 @@ public void isValid(String formula) { } public Integer calcualteFormula() { - result = calculator.calculate(getInfixListFormula()); + result = calculator.calculate(this); return result; }