From f23adfd1038deadaefd2d87d70326ce69f6ed526 Mon Sep 17 00:00:00 2001 From: jhm9595 Date: Sun, 13 Apr 2025 22:53:00 +0900 Subject: [PATCH 1/2] =?UTF-8?q?refactor=20:=20Stream,=20Optional=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++++- src/main/java/nextstep/fp/Car.java | 7 ++++- src/main/java/nextstep/fp/Conditional.java | 5 ++++ src/main/java/nextstep/fp/Lambda.java | 14 ++-------- src/main/java/nextstep/fp/StreamStudy.java | 27 ++++++++++++------- .../java/nextstep/optional/Expression.java | 12 ++++----- src/main/java/nextstep/optional/User.java | 7 ++++- src/main/java/nextstep/optional/Users.java | 11 ++++---- src/test/java/nextstep/fp/CarTest.java | 15 +++-------- src/test/java/nextstep/fp/LambdaTest.java | 4 +-- 10 files changed, 60 insertions(+), 51 deletions(-) create mode 100644 src/main/java/nextstep/fp/Conditional.java diff --git a/README.md b/README.md index b853592f59..1d88ddd56d 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,11 @@ * 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다. ## 온라인 코드 리뷰 과정 -* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/nextstep-step/nextstep-docs/tree/master/codereview) \ No newline at end of file +* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/nextstep-step/nextstep-docs/tree/master/codereview) + +# 기능 요구사항 +* 사다리 게임에 참여하는 사람에 이름을 최대5글자까지 부여할 수 있다. 사다리를 출력할 때 사람 이름도 같이 출력한다. +* 사람 이름은 쉼표(,)를 기준으로 구분한다. +* 사람 이름을 5자 기준으로 출력하기 때문에 사다리 폭도 넓어져야 한다. +* 사다리 타기가 정상적으로 동작하려면 라인이 겹치지 않도록 해야 한다. +* |-----|-----| 모양과 같이 가로 라인이 겹치는 경우 어느 방향으로 이동할지 결정할 수 없다. diff --git a/src/main/java/nextstep/fp/Car.java b/src/main/java/nextstep/fp/Car.java index 2146c11290..669724cd76 100644 --- a/src/main/java/nextstep/fp/Car.java +++ b/src/main/java/nextstep/fp/Car.java @@ -2,7 +2,7 @@ import java.util.Objects; -public class Car { +public class Car implements Conditional{ private final String name; private final int position; @@ -32,4 +32,9 @@ public int hashCode() { return Objects.hash(name, position); } + + @Override + public boolean test(Integer number) { + return false; + } } diff --git a/src/main/java/nextstep/fp/Conditional.java b/src/main/java/nextstep/fp/Conditional.java new file mode 100644 index 0000000000..1d48b1b856 --- /dev/null +++ b/src/main/java/nextstep/fp/Conditional.java @@ -0,0 +1,5 @@ +package nextstep.fp; + +public interface Conditional { + boolean test(Integer number); +} diff --git a/src/main/java/nextstep/fp/Lambda.java b/src/main/java/nextstep/fp/Lambda.java index bd68fe1ce6..9e3ea8ebbb 100644 --- a/src/main/java/nextstep/fp/Lambda.java +++ b/src/main/java/nextstep/fp/Lambda.java @@ -34,20 +34,10 @@ public static int sumAll(List numbers) { return total; } - public static int sumAllEven(List numbers) { + public static int sumAll(List numbers, Conditional c) { int total = 0; for (int number : numbers) { - if (number % 2 == 0) { - total += number; - } - } - return total; - } - - public static int sumAllOverThree(List numbers) { - int total = 0; - for (int number : numbers) { - if (number > 3) { + if(c.test(number)) { total += number; } } diff --git a/src/main/java/nextstep/fp/StreamStudy.java b/src/main/java/nextstep/fp/StreamStudy.java index b446983a02..ffb4baf08f 100644 --- a/src/main/java/nextstep/fp/StreamStudy.java +++ b/src/main/java/nextstep/fp/StreamStudy.java @@ -5,21 +5,19 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; +import static java.util.stream.Collectors.*; public class StreamStudy { public static long countWords() throws IOException { String contents = new String(Files.readAllBytes(Paths .get("src/main/resources/fp/war-and-peace.txt")), StandardCharsets.UTF_8); - List words = Arrays.asList(contents.split("[\\P{L}]+")); - long count = 0; - for (String w : words) { - if (w.length() > 12) count++; - } - return count; + return Arrays.stream(contents.split("[\\P{L}]+")) + .filter(w-> w.length() > 12) + .count(); } public static void printLongestWordTop100() throws IOException { @@ -27,11 +25,17 @@ public static void printLongestWordTop100() throws IOException { .get("src/main/resources/fp/war-and-peace.txt")), StandardCharsets.UTF_8); List words = Arrays.asList(contents.split("[\\P{L}]+")); - // TODO 이 부분에 구현한다. + words.stream() + .filter(word -> word.length() > 12) + .sorted(Comparator.reverseOrder()) + .distinct() + .map(String::toLowerCase) + .limit(100) + .forEach(System.out::println); } public static List doubleNumbers(List numbers) { - return numbers.stream().map(x -> 2 * x).collect(Collectors.toList()); + return numbers.stream().map(x -> 2 * x).collect(toList()); } public static long sumAll(List numbers) { @@ -39,6 +43,9 @@ public static long sumAll(List numbers) { } public static long sumOverThreeAndDouble(List numbers) { - return 0; + return numbers.stream() + .filter(number -> number > 3) + .mapToInt(number -> number * 2) + .sum(); } } \ No newline at end of file diff --git a/src/main/java/nextstep/optional/Expression.java b/src/main/java/nextstep/optional/Expression.java index 1c98cd6a62..463a1a6c7c 100644 --- a/src/main/java/nextstep/optional/Expression.java +++ b/src/main/java/nextstep/optional/Expression.java @@ -1,5 +1,7 @@ package nextstep.optional; +import java.util.Arrays; + enum Expression { PLUS("+"), MINUS("-"), TIMES("*"), DIVIDE("/"); @@ -14,12 +16,10 @@ private static boolean matchExpression(Expression e, String expression) { } static Expression of(String expression) { - for (Expression v : values()) { - if (matchExpression(v, expression)) { - return v; - } - } - throw new IllegalArgumentException(String.format("%s는 사칙연산에 해당하지 않는 표현식입니다.", expression)); + return Arrays.stream(values()) + .filter(v->matchExpression(v, expression)) + .findAny() + .orElseThrow(()-> new IllegalArgumentException(String.format("%s는 사칙연산에 해당하지 않는 표현식입니다.", expression))); } } diff --git a/src/main/java/nextstep/optional/User.java b/src/main/java/nextstep/optional/User.java index 9614c2f43f..d96ba766fa 100644 --- a/src/main/java/nextstep/optional/User.java +++ b/src/main/java/nextstep/optional/User.java @@ -1,5 +1,7 @@ package nextstep.optional; +import java.util.Optional; + public class User { private String name; private Integer age; @@ -33,7 +35,10 @@ public static boolean ageIsInRange1(User user) { } public static boolean ageIsInRange2(User user) { - return false; + return Optional.ofNullable(user) + .filter(u-> u.getAge() >= 30) + .filter(u-> u.getAge() <= 45) + .isPresent(); } @Override diff --git a/src/main/java/nextstep/optional/Users.java b/src/main/java/nextstep/optional/Users.java index 6293040de8..0ce1530473 100644 --- a/src/main/java/nextstep/optional/Users.java +++ b/src/main/java/nextstep/optional/Users.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.List; +import java.util.Optional; public class Users { static final User DEFAULT_USER = new User("codesquad", 100); @@ -13,11 +14,9 @@ public class Users { new User("honux", 45)); User getUser(String name) { - for (User user : users) { - if (user.matchName(name)) { - return user; - } - } - return DEFAULT_USER; + return users.stream() + .filter(user->user.matchName(name)) + .findAny() + .orElse(DEFAULT_USER); } } diff --git a/src/test/java/nextstep/fp/CarTest.java b/src/test/java/nextstep/fp/CarTest.java index 1ab1106fe2..a570bb6140 100644 --- a/src/test/java/nextstep/fp/CarTest.java +++ b/src/test/java/nextstep/fp/CarTest.java @@ -8,24 +8,15 @@ public class CarTest { @Test public void 이동() { Car car = new Car("pobi", 0); - Car actual = car.move(new MoveStrategy() { - @Override - public boolean isMovable() { - return true; - } - }); + + Car actual = car.move(()-> true); assertThat(actual).isEqualTo(new Car("pobi", 1)); } @Test public void 정지() { Car car = new Car("pobi", 0); - Car actual = car.move(new MoveStrategy() { - @Override - public boolean isMovable() { - return false; - } - }); + Car actual = car.move(() -> false); assertThat(actual).isEqualTo(new Car("pobi", 0)); } } diff --git a/src/test/java/nextstep/fp/LambdaTest.java b/src/test/java/nextstep/fp/LambdaTest.java index f240ac6560..2376d4d313 100644 --- a/src/test/java/nextstep/fp/LambdaTest.java +++ b/src/test/java/nextstep/fp/LambdaTest.java @@ -39,13 +39,13 @@ public void sumAll() throws Exception { @Test public void sumAllEven() throws Exception { - int sum = Lambda.sumAllEven(numbers); + int sum = Lambda.sumAll(numbers, number -> number % 2 == 0); assertThat(sum).isEqualTo(12); } @Test public void sumAllOverThree() throws Exception { - int sum = Lambda.sumAllOverThree(numbers); + int sum = Lambda.sumAll(numbers, number -> number > 3); assertThat(sum).isEqualTo(15); } } From 4128ad1d340543824dbdc4ed06b092f93469a81c Mon Sep 17 00:00:00 2001 From: jhm9595 Date: Tue, 22 Apr 2025 22:59:22 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat=20:=20Ladder=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++ src/main/java/nextstep/LadderApplication.java | 26 +++++++++++ src/main/java/nextstep/domain/Line.java | 30 ++++++++++++ src/main/java/nextstep/util/RandomUtils.java | 12 +++++ src/main/java/nextstep/util/StringUtils.java | 19 ++++++++ src/main/java/nextstep/view/InputView.java | 36 +++++++++++++++ src/main/java/nextstep/view/ResultView.java | 46 +++++++++++++++++++ 7 files changed, 173 insertions(+) create mode 100644 src/main/java/nextstep/LadderApplication.java create mode 100644 src/main/java/nextstep/domain/Line.java create mode 100644 src/main/java/nextstep/util/RandomUtils.java create mode 100644 src/main/java/nextstep/util/StringUtils.java create mode 100644 src/main/java/nextstep/view/InputView.java create mode 100644 src/main/java/nextstep/view/ResultView.java diff --git a/README.md b/README.md index 1d88ddd56d..e1ee5ed959 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,7 @@ * 사람 이름을 5자 기준으로 출력하기 때문에 사다리 폭도 넓어져야 한다. * 사다리 타기가 정상적으로 동작하려면 라인이 겹치지 않도록 해야 한다. * |-----|-----| 모양과 같이 가로 라인이 겹치는 경우 어느 방향으로 이동할지 결정할 수 없다. + +# 프로그래밍 요구사항 +* 자바 8의 스트림과 람다를 적용해 프로그래밍한다. +* 규칙 6: 모든 엔티티를 작게 유지한다. diff --git a/src/main/java/nextstep/LadderApplication.java b/src/main/java/nextstep/LadderApplication.java new file mode 100644 index 0000000000..6508780ec3 --- /dev/null +++ b/src/main/java/nextstep/LadderApplication.java @@ -0,0 +1,26 @@ +package nextstep; + +import nextstep.domain.Line; +import nextstep.view.InputView; +import nextstep.view.ResultView; + +import java.util.LinkedList; + +public class LadderApplication { + + public static void main(String[] args) { + + String[] names = InputView.inputNames(); + + int ladderHeight = InputView.inputLadderHeight(); + + LinkedList lines = new LinkedList<>(); + lines.add(new Line(ladderHeight)); // 첫번째 라인은 랜덤으로 생성 + + for (int i = 1; i < names.length - 1; i++) { + lines.addLast(new Line(lines.getLast())); + } + + ResultView.printResult(names, ladderHeight, lines); + } +} diff --git a/src/main/java/nextstep/domain/Line.java b/src/main/java/nextstep/domain/Line.java new file mode 100644 index 0000000000..26e44fba43 --- /dev/null +++ b/src/main/java/nextstep/domain/Line.java @@ -0,0 +1,30 @@ +package nextstep.domain; + +import nextstep.util.RandomUtils; + +import java.util.ArrayList; +import java.util.List; + +public class Line { + private List points = new ArrayList<>(); + + public List getPoints() { + return points; + } + + public boolean isPoint(int idx) { + return points.get(idx); + } + + public Line(int height) { + for (int i = 0; i < height; i++) { + points.add(RandomUtils.nextBoolean()); + } + } + + public Line(Line previousLine) { + for (Boolean hasPoint : previousLine.getPoints()) { + points.add(!hasPoint && RandomUtils.nextBoolean()); + } + } +} diff --git a/src/main/java/nextstep/util/RandomUtils.java b/src/main/java/nextstep/util/RandomUtils.java new file mode 100644 index 0000000000..ff5916f338 --- /dev/null +++ b/src/main/java/nextstep/util/RandomUtils.java @@ -0,0 +1,12 @@ +package nextstep.util; + +import java.util.Random; + +public class RandomUtils { + + private static final Random random = new Random(); + + public static boolean nextBoolean() { + return random.nextBoolean(); + } +} diff --git a/src/main/java/nextstep/util/StringUtils.java b/src/main/java/nextstep/util/StringUtils.java new file mode 100644 index 0000000000..504a53e1d4 --- /dev/null +++ b/src/main/java/nextstep/util/StringUtils.java @@ -0,0 +1,19 @@ +package nextstep.util; + +public class StringUtils { + + public static String lpad(String name, int maxLength) { + + int length = name.length(); + + if (length > maxLength) { + throw new IllegalArgumentException("사람 이름을 5자를 넘지 못합니다."); + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i <= maxLength - name.length(); i++) { + sb.append(" "); + } + return sb.toString() + name; + } +} diff --git a/src/main/java/nextstep/view/InputView.java b/src/main/java/nextstep/view/InputView.java new file mode 100644 index 0000000000..45d25b3fd9 --- /dev/null +++ b/src/main/java/nextstep/view/InputView.java @@ -0,0 +1,36 @@ +package nextstep.view; + +import java.util.Scanner; + +public class InputView { + + private static final int MIN_LADDER_HEIGHT = 1; + private static final int MIN_NAME_LENGTH = 2; + + private static final Scanner scanner = new Scanner(System.in); + + + public static String[] inputNames(){ + + System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); + + String[] names = scanner.next().split(","); + + if(names.length < MIN_NAME_LENGTH){ + throw new IllegalArgumentException("최소 2명 이상이어야 합니다."); + } + + return names; + } + + public static int inputLadderHeight() { + + System.out.println("최대 사다리 높이는 몇 개인가요?"); + int ladderHeight = scanner.nextInt(); + + if(ladderHeight < MIN_LADDER_HEIGHT){ + throw new IllegalArgumentException("높이는 1 이상이여야 합니다."); + } + return ladderHeight; + } +} diff --git a/src/main/java/nextstep/view/ResultView.java b/src/main/java/nextstep/view/ResultView.java new file mode 100644 index 0000000000..477b77aa1c --- /dev/null +++ b/src/main/java/nextstep/view/ResultView.java @@ -0,0 +1,46 @@ +package nextstep.view; + +import nextstep.domain.Line; +import nextstep.util.StringUtils; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.stream.IntStream; + +public class ResultView { + + public static final String EMPTY_LADDER = " "; + public static final String FULL_LADDER = "-----"; + public static final String PIPE = "|"; + public static final int MAX_NAME_LENGTH = 5; + public static final String NL = System.lineSeparator(); + + + public static void printResult(String[] names, int ladderHeight, LinkedList lines) { + + StringBuilder sb = new StringBuilder(); + + sb.append("실행 결과") + .append(NL) + .append(Arrays.stream(names) + .map(name -> StringUtils.lpad(name, MAX_NAME_LENGTH)) + .reduce("", String::concat)) + .append(NL); + + IntStream.range(0, ladderHeight) + .forEach(idx -> { + sb.append(EMPTY_LADDER) + .append(lines.stream() + .map(line -> draw(line.isPoint(idx))) + .reduce("", String::concat)) + .append(PIPE) + .append(NL); + }); + + System.out.println(sb.toString()); + } + + private static String draw(boolean point) { + return PIPE.concat(point ? FULL_LADDER : EMPTY_LADDER); + } +}