diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..5af9368b --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar +/out/ +/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +# IntelliJ project files +out +gen diff --git "a/10weeks/Collection.forEach\354\231\200 Stream.forEach\354\235\230 \354\260\250\354\235\264.md" "b/10weeks/Collection.forEach\354\231\200 Stream.forEach\354\235\230 \354\260\250\354\235\264.md" new file mode 100644 index 00000000..2ee7816e --- /dev/null +++ "b/10weeks/Collection.forEach\354\231\200 Stream.forEach\354\235\230 \354\260\250\354\235\264.md" @@ -0,0 +1,55 @@ +# Collection.forEach와 Stream.forEach의 차이 +```java +public void print(List nums) { + nums.forEach(System.out::println); + nums.stream().forEach(System.out::println); +} +``` +Collection.forEach는 따로 객체를 생성하지 않고 forEach 메서드를 호출한다. forEach 메서드는 Iterable 인터페이스의 default 메서드인데, Collection 인터페이스에서 Iterable 인터페이스를 상속하고 있기에 바로 호출할 수 있는 것이다. + +```java +public interface Iterable { + default void forEach(Consumer action) { + Objects.requireNonNull(action); + for (T t : this) { + action.accept(t); + } + } + ... +} +public interface Collection extends Iterable { + ... +} +``` +반면에 Stream.forEach는 Collection 인터페이스의 default 메서드 stream()으로 Stream 객체를 생성해야만 forEach를 호출할 수 있다. + +## parallelStream +stream 메소드로 생성한 Stream.forEach를 했을 땐 Collection.forEach와 별 차이가 없었지만 Collection 인터페이스의 또다른 Stream 객체 생성 메소드 parallelStream()을 사용해서 Stream.forEach를 한다면 그 차이점이 명확하다. + +```java +public void print() { + List nums = Arrays.asList(1, 2, 3, 4, 5); + System.out.println("Collection.forEach 출력 시작"); + nums.forEach(System.out::println); + System.out.println("Stream.forEach 출력 시작"); + nums.parallelStream().forEach(System.out::println); +} + +//실행 결과 +Collection.forEach 출력 시작 +1 +2 +3 +4 +5 +Stream.forEach 출력 시작 +3 +4 +1 +5 +2 +``` +parallelStream 메소드로 생성한 Stream 객체는 여러 스레드에서 스트림을 실행하기 때문에 forEach를 했을 때 실행 순서가 매번 달라지며 예측 불가능하다. + +## Reference +- [Collection.forEach와 Stream.forEach는 뭐가 다를까?](https://dundung.tistory.com/247) \ No newline at end of file diff --git "a/10weeks/Stream\354\235\230 \355\212\271\354\247\225 \354\240\225\353\246\254.md" "b/10weeks/Stream\354\235\230 \355\212\271\354\247\225 \354\240\225\353\246\254.md" new file mode 100644 index 00000000..03b8c91d --- /dev/null +++ "b/10weeks/Stream\354\235\230 \355\212\271\354\247\225 \354\240\225\353\246\254.md" @@ -0,0 +1,54 @@ +# Stream 특징 정리 +## map() +- 스트림의 각 요소마다 수행할 연산을 구현할 때 사용한다. +```java +intList.stream().map(x -> x*x).forEach(System.out::println); // 1,4,9 +``` + +## filter() +- 스트림 요소를 필터링 하기 위한 메소드이다. +- filter()는 스트림 요소마다 비교문을 만족하는 요소로 구성된 스트림을 반환한다. +- 특정 조건에 맞는 값만 추리기 위한 용도로 사용한다. +```java +intList.stream().filter(x -> x<=2).forEach(System.out::println); // 1,2 +``` + +## sorted() +- 스트림 요소를 정렬하는 메소드로 기본적으로 오름차순으로 정렬한다. +- sorted() 활용하는 방법은 몇 가지가 있는데 스트림 원소가 Comparable 인터페이스를 구현하고 있는 상태라면 다음과 같이 하면 된다. + +Comparable 인터페이스 구현은 오름차순이라고 가정한다. +```java +Arrays.asList(1,4,3,2).stream().sorted().forEach(System.out::println); // 1,2,3,4 +Arrays.asList(1,4,3,2).stream().sorted((a,b) -> b.compareTo(a)).forEach(System.out::println); // 4,3,2,1 +Arrays.asList(1,4,3,2).stream().sorted( (a,b) -> -a.compareTo(b)).forEach(System.out::println); // 4,3,2,1 +``` +두번째와 세번째 방법은 오름차순 구현을 활용해 내림차순으로 처리할 때 사용할 수 있는 방법 이다. +내림차순 정렬을 위한 또다른 방법은 -a.compareTo(b) 를 사용하는 것인데 직관적이지 못해 권장하지는 않는다. + +정렬에 사용되는 또다른 방법은 Comparator를 사용하는 것으로 새로운 정렬 조건을 지정하고자 한다면 sorted((a,b) -> { })와 같이 코드를 작성하면 된다. +```java +Arrays.asList(1,4,3,2).stream().sorted( Comparator.reverseOrder()).forEach(System.out::println); // 4,3,2,1 +``` + +## distinct() +- distict()는 요소들의 중복을 제거하고 스트림을 반환한다. +```java +Arrays.asList(1,2,3,2,5).stream().distinct().forEach(System.out::println); // 1,2,3,5 +``` + +## limit() +- 스트림의 시작 요소로부터 인자로 전달된 인덱스까지의 요소를 추출해 새로운 스트림을 생성한다. +```java +intList.stream().limit(2).forEach(System.out::println); // 1,2 +``` + +## forEach() +- 스트림의 요소들을 순환하면서 반복해서 처리해야 하는 경우 사용한다. +```java +intList.stream().forEach(System.out::println); // 1,2,3 +intList.stream().forEach(x -> System.out.printf("%d : %d\n",x,x*x)); // 1,4,9 +``` + +## Reference +- [[Java] Stream](https://velog.io/@gillog/Java-Stream-Class) \ No newline at end of file diff --git a/10weeks/racingcar/build.gradle b/10weeks/racingcar/build.gradle new file mode 100644 index 00000000..95687b5b --- /dev/null +++ b/10weeks/racingcar/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group 'org.example' +version '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/10weeks/racingcar/build/classes/java/main/Application.class b/10weeks/racingcar/build/classes/java/main/Application.class new file mode 100644 index 00000000..16ee0685 Binary files /dev/null and b/10weeks/racingcar/build/classes/java/main/Application.class differ diff --git a/10weeks/racingcar/build/classes/java/main/racingcar/Car.class b/10weeks/racingcar/build/classes/java/main/racingcar/Car.class new file mode 100644 index 00000000..47c39e84 Binary files /dev/null and b/10weeks/racingcar/build/classes/java/main/racingcar/Car.class differ diff --git a/10weeks/racingcar/build/classes/java/main/racingcar/Cars.class b/10weeks/racingcar/build/classes/java/main/racingcar/Cars.class new file mode 100644 index 00000000..d1df5f7d Binary files /dev/null and b/10weeks/racingcar/build/classes/java/main/racingcar/Cars.class differ diff --git a/10weeks/racingcar/build/classes/java/main/utils/GameUtils.class b/10weeks/racingcar/build/classes/java/main/utils/GameUtils.class new file mode 100644 index 00000000..e5318caa Binary files /dev/null and b/10weeks/racingcar/build/classes/java/main/utils/GameUtils.class differ diff --git a/10weeks/racingcar/build/classes/java/main/utils/RandomUtils.class b/10weeks/racingcar/build/classes/java/main/utils/RandomUtils.class new file mode 100644 index 00000000..28cdcbe6 Binary files /dev/null and b/10weeks/racingcar/build/classes/java/main/utils/RandomUtils.class differ diff --git a/10weeks/racingcar/build/classes/java/main/view/InputView.class b/10weeks/racingcar/build/classes/java/main/view/InputView.class new file mode 100644 index 00000000..673a1f44 Binary files /dev/null and b/10weeks/racingcar/build/classes/java/main/view/InputView.class differ diff --git a/10weeks/racingcar/build/tmp/compileJava/source-classes-mapping.txt b/10weeks/racingcar/build/tmp/compileJava/source-classes-mapping.txt new file mode 100644 index 00000000..2d3c0dab --- /dev/null +++ b/10weeks/racingcar/build/tmp/compileJava/source-classes-mapping.txt @@ -0,0 +1,12 @@ +utils/GameUtils.java + utils.GameUtils +Application.java + Application +view/InputView.java + view.InputView +racingcar/Car.java + racingcar.Car +racingcar/Cars.java + racingcar.Cars +utils/RandomUtils.java + utils.RandomUtils diff --git a/10weeks/racingcar/gradle/wrapper/gradle-wrapper.jar b/10weeks/racingcar/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and b/10weeks/racingcar/gradle/wrapper/gradle-wrapper.jar differ diff --git a/10weeks/racingcar/gradle/wrapper/gradle-wrapper.properties b/10weeks/racingcar/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..be52383e --- /dev/null +++ b/10weeks/racingcar/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/10weeks/racingcar/gradlew b/10weeks/racingcar/gradlew new file mode 100644 index 00000000..4f906e0c --- /dev/null +++ b/10weeks/racingcar/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/10weeks/racingcar/gradlew.bat b/10weeks/racingcar/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/10weeks/racingcar/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/10weeks/racingcar/settings.gradle b/10weeks/racingcar/settings.gradle new file mode 100644 index 00000000..563821bb --- /dev/null +++ b/10weeks/racingcar/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'racingcar' + diff --git a/10weeks/racingcar/src/main/java/Application.java b/10weeks/racingcar/src/main/java/Application.java new file mode 100644 index 00000000..a16bc9a2 --- /dev/null +++ b/10weeks/racingcar/src/main/java/Application.java @@ -0,0 +1,8 @@ +import racingcar.Game; + +public class Application { + public static void main(String[] args) { + Game game = new Game(); + game.start(); + } +} \ No newline at end of file diff --git a/10weeks/racingcar/src/main/java/racingcar/Car.java b/10weeks/racingcar/src/main/java/racingcar/Car.java new file mode 100644 index 00000000..823f0148 --- /dev/null +++ b/10weeks/racingcar/src/main/java/racingcar/Car.java @@ -0,0 +1,33 @@ +package racingcar; + +import utils.RandomUtils; +import utils.CarNameValidator; + +public class Car { + private static final int FIRST_DIGIT = 0; + private static final int LAST_DIGIT = 9; + private static final int POINT_DIGIT = 4; + + private final String name; + private int position = 0; + + public Car(String name) { + CarNameValidator.validateName(name); + this.name = name; + } + + public String getName(){ + return name; + } + + public int getPosition(){ + return position; + } + + public void move() { + int randomNumber = RandomUtils.nextInt(FIRST_DIGIT, LAST_DIGIT); + if (randomNumber >= POINT_DIGIT) { + position++; + } + } +} diff --git a/10weeks/racingcar/src/main/java/racingcar/Cars.java b/10weeks/racingcar/src/main/java/racingcar/Cars.java new file mode 100644 index 00000000..d8ba4f70 --- /dev/null +++ b/10weeks/racingcar/src/main/java/racingcar/Cars.java @@ -0,0 +1,35 @@ + +package racingcar; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +public class Cars { + private List cars; + + public Cars(List carNames) { + this.cars = carNames.stream() + .map(Car::new) + .collect(Collectors.toList()); + } + + public List run() { + for (Car car: cars) { + car.move(); + } + return cars; + } + + public Winner findWinner() { + int maxPosition = cars.stream() + .max(Comparator.comparing(Car::getPosition)) + .orElseThrow() + .getPosition(); + List winners = cars.stream() + .filter(car -> car.getPosition() == maxPosition) + .collect(Collectors.toList()); + + return new Winner(winners); + } +} \ No newline at end of file diff --git a/10weeks/racingcar/src/main/java/racingcar/Game.java b/10weeks/racingcar/src/main/java/racingcar/Game.java new file mode 100644 index 00000000..d8b46064 --- /dev/null +++ b/10weeks/racingcar/src/main/java/racingcar/Game.java @@ -0,0 +1,21 @@ +package racingcar; + +import view.InputView; +import view.ResultView; + +public class Game { + + public void start() { + Cars cars = new Cars(InputView.inputCarName()); + int gameNumber = InputView.inputNumber(); + + ResultView.printResultTitle(); + + for (int i = 0; i < gameNumber; i++) { + ResultView.printResultPosition(cars.run()); + System.out.println(); + } + + ResultView.printWinners(cars.findWinner()); + } +} \ No newline at end of file diff --git a/10weeks/racingcar/src/main/java/racingcar/Winner.java b/10weeks/racingcar/src/main/java/racingcar/Winner.java new file mode 100644 index 00000000..589924a4 --- /dev/null +++ b/10weeks/racingcar/src/main/java/racingcar/Winner.java @@ -0,0 +1,18 @@ +package racingcar; + +import java.util.List; +import java.util.stream.Collectors; + +public class Winner { + private List cars; + + public Winner(List cars) { + this.cars = cars; + } + + public List getWinnersName() { + return cars.stream() + .map(Car::getName) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/10weeks/racingcar/src/main/java/utils/CarNameValidator.java b/10weeks/racingcar/src/main/java/utils/CarNameValidator.java new file mode 100644 index 00000000..658f5178 --- /dev/null +++ b/10weeks/racingcar/src/main/java/utils/CarNameValidator.java @@ -0,0 +1,24 @@ +package utils; + +public class CarNameValidator { + private static final int MAX_NAME_LENGTH = 5; + + private CarNameValidator() { } + + public static void validateName(String carName) { + emptyCheck(carName); + lengthCheck(carName); + } + + public static void emptyCheck(String carName) { + if (carName == "") { + throw new IllegalArgumentException("[ERROR] 자동차 이름을 입력하지 않았습니다."); + } + } + + public static void lengthCheck(String carName) { + if (carName.length() > MAX_NAME_LENGTH) { + throw new IllegalArgumentException("[ERROR] 자동차 이름은 5자 이하로만 가능합니다."); + } + } +} diff --git a/10weeks/racingcar/src/main/java/utils/RandomUtils.java b/10weeks/racingcar/src/main/java/utils/RandomUtils.java new file mode 100644 index 00000000..f951aecf --- /dev/null +++ b/10weeks/racingcar/src/main/java/utils/RandomUtils.java @@ -0,0 +1,27 @@ +package utils; + +import java.util.Random; + +public class RandomUtils { + private static final Random RANDOM = new Random(); + + private RandomUtils() { + + } + + public static int nextInt(final int startInclusive, final int endInclusive) { + if (startInclusive > endInclusive) { + throw new IllegalArgumentException("[ERROR] Random 값이 잘못 되었습니다."); + } + + if (startInclusive < 0) { + throw new IllegalArgumentException("[ERROR] Random 값이 잘못 되었습니다."); + } + + if (startInclusive == endInclusive) { + return startInclusive; + } + + return startInclusive + RANDOM.nextInt(endInclusive - startInclusive + 1); + } +} \ No newline at end of file diff --git a/10weeks/racingcar/src/main/java/view/InputView.java b/10weeks/racingcar/src/main/java/view/InputView.java new file mode 100644 index 00000000..21941bd5 --- /dev/null +++ b/10weeks/racingcar/src/main/java/view/InputView.java @@ -0,0 +1,26 @@ +package view; + +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +public class InputView { + private static final Scanner SCANNER = new Scanner(System.in); + + private InputView() { } + + public static List inputCarName(){ + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + return Arrays.asList(SCANNER.nextLine().split(",")); + } + + public static int inputNumber(){ + System.out.println("시도할 회수는 몇회인가요?"); + try { + int number = SCANNER.nextInt(); + return number; + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("[ERROR] 숫자가 아닌 문자를 입력하셨습니다.\n"); + } + } +} \ No newline at end of file diff --git a/10weeks/racingcar/src/main/java/view/ResultView.java b/10weeks/racingcar/src/main/java/view/ResultView.java new file mode 100644 index 00000000..af21e418 --- /dev/null +++ b/10weeks/racingcar/src/main/java/view/ResultView.java @@ -0,0 +1,35 @@ +package view; + +import racingcar.Car; +import racingcar.Winner; + +import java.util.List; + +public class ResultView { + private static final String POSITION = "-"; + + private ResultView() { } + + public static void printResultTitle(){ + System.out.println(); + System.out.println("실행 결과"); + } + + public static void printResultPosition(List cars){ + for(Car car : cars) { + printCarPosition(car); + } + } + + public static void printCarPosition(Car car) { + System.out.print(car.getName() + " : "); + for (int i = 0; i < car.getPosition(); i++) { + System.out.print(POSITION); + } + System.out.println(); + } + + public static void printWinners(Winner winner) { + System.out.println("최종 우승자: " + winner.getWinnersName()); + } +} \ No newline at end of file diff --git "a/10weeks/\354\273\254\353\240\211\354\205\230 \355\224\204\353\240\210\354\236\204 \354\233\214\355\201\254.md" "b/10weeks/\354\273\254\353\240\211\354\205\230 \355\224\204\353\240\210\354\236\204 \354\233\214\355\201\254.md" new file mode 100644 index 00000000..e3aaee88 --- /dev/null +++ "b/10weeks/\354\273\254\353\240\211\354\205\230 \355\224\204\353\240\210\354\236\204 \354\233\214\355\201\254.md" @@ -0,0 +1,75 @@ +# 컬렉션 프레임 워크 +배열은 고정 크기 이상의 객체를 관리할 수 없으며 배열의 중간에 객체가 삭제되면 해당 인덱스의 데이터가 비어있어 메모리가 낭비되는 등 여러가지 문제점이 발생한다. 컬렉션은 배열의 문제점을 해결하기 위해 객체나 데이터들을 효율적으로 관리할 수 있는 자료구조들을 만들어 놓았다. 이러한 자료구조들이 있는 라이브러리를 **컬렉션 프레임워크**라고 한다. +## 컬렉션 +- 요소(element) 객체들의 저장소 + - 객체들의 컨테이너라고도 불림 + - 요소의 개수에 따라 크기 자동 조절 + - 요소 삽입, 삭제에 따른 요소의 위치 자동 이동 +- 고정 크기의 배열을 다루는 어려움 해소 +- 다양한 객체들의 삽입, 삭제, 검색 등의 관리 용이 +![컬렉션 프레임워크](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdy438%2FbtqEjPZKIY0%2Fe5Wm8ZJmdRNza4tKBzaK6k%2Fimg.png) + +## List 컬렉션 +List 컬렉션은 객체를 일렬로 늘어놓은 구조를 가지고 있다. List 컬렉션은 객체를 인덱스로 관리하기 때문에 객체를 저장하면 자동 인덱스가 부여되고 인덱스로 객체를 검색, 삭제 등을 할 수 있는 기능을 제공한다. +![List컬렉션](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxhCVv%2FbtqEg09LXoG%2Fm26SctApZoPjJtRaAEmlSk%2Fimg.png) +- List 컬렉션은 객체 자체를 저장하는 것이 아니라 위와 같이 객체의 번지를 참조한다. +- 동일한 객체를 중복 저장할 수 있는데 이 경우 동일한 번지가 참조된다. +- List 컬렉션을 구현하는 대표적인 클래스들은 ArrayList, LinkedList, Vector가 있으며 이 3가지 클래스는 List 인터페이스를 같이 상속하고 있으므로 공통적으로 사용할 수 있는 메소드들이 존재한다. + +List 클래스의 주요 메소드 +|메소드|설명| +|:---:|:---:| +|boolean add(E e)|주어진 객체를 맨 끝에 추가| +|void add(int index, E element)|주어진 인덱스에 객체를 추가| +|set(int index, E element)|주어진 인덱스에 저장된 객체를 주어진 객체로 바꿈| +|boolean contains(Object o)|주어진 객체가 있는지에 대한 여부를 검색| +|E get(int index)|주어진 인덱스에 저장된 객체를 리턴| +|isEmpty()|컬렉션이 비어있는지 여부를 확인| +|int size()|저장되어 있는 전체 객체 수를 리턴| +|E remove(int index)|주어진 인덱스에 저장된 객체를 삭제| +|void clear()|주어진 인덱스에 저장된 객체를 삭제| +|boolean remove(Object o)|주어진 객체를 삭제| + +## Set 컬렉션 +앞서 살펴본 List 컬렉션은 선형구조를 가지고 있으므로 추가한 순서대로 저장이 되어 순서를 유지하였지만 Set 컬렉션의 경우에는 저장 순서가 유지되지 않는다. 그렇기에 Set 컬렉션은 순서 자체가 없으므로 인덱스로 객체를 검색해서 가져오는 get(index) 메서드도 존재하지 않는다. 대신 전체 객체를 대상으로 한 번씩 반복해서 가져오는 반복자(Iterator)를 제공한다. +![Set 컬렉션](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLMuJG%2FbtqEgQzQaFv%2F18xV7JmoktO3gKPnYitGZ0%2Fimg.png) +- Set 컬렉션은 객체를 중복해서 저장할 수 없다. +- NULL 값도 하나만 저장된다. +- Set 컬렉션을 구현하는 대표적인 클래스들은 HashSet과 TreeSet이 있으며 Set 인터페이스를 같이 상속하고 있으므로 공통적으로 사용할 수 있는 메소드들이 존재한다. + +Set 클래스의 주요 메소드 +|메소드|설명| +|:---:|:---:| +|boolean add(E e)|주어진 객체를 저장 후 성공적이면 true를 중복 객체면 false를 리턴| +|boolean contains(Object o)|주어진 객체가 저장되어있는지 여부를 리턴| +|Iterator iterator()|저장된 객체를 한번씩 가져오는 반복자를 리턴| +|isEmpty()|컬렉션이 비어있는지 조사| +|int Size()|저장되어 있는 전체 객체수를 리턴| +|void clear()|저장된 모든 객체를 삭제| +|boolean remove(Object o)|주어진 객체를 삭제| + +## Map 컬렉션 +Map 컬렉션은 Key와 Value라는 것을 한 쌍으로 갖는 자료형이다. Map 컬렉션은 리스트나 배열처럼 순차적으로 해당 요소 값을 구하지 않고 key를 통해 value를 얻는다. 따라서 Map 컬렉션은 키로 데이터를 관리한다. +![Map 컬렉션](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDaHeK%2FbtqEjQx07Ng%2FPQSBhv0USEnMzQnzuMFw61%2Fimg.png) +- Map 컬렉션은 키와 값으로 구성된 객체를 저장하는 구조를 가지고 있는 자료구조이다. +- 키는 중복으로 저장할 수 없고 값은 중복으로 저장할 수 있다. +- 중복된 key값이 들어온다면 기존의 값은 없어지고 새로운 값으로 대치된다. +- Map 컬렉션을 구현하는 대표적인 클래스들은 HashMap, Hashtable, LinkedHashMap, TreeMap 등이 있으며 Map 인터페이스를 같이 상속하고 있으므로 공통적으로 사용할 수 있는 메소드들이 존재한다. + +Map 클래스의 주요 메소드 +|메소드|설명| +|:---:|:---:| +|V put(K Key, V value)|주어진 키와 값을 추가하여 저장되면 값을 리턴| +|boolean containsKey(Object Key)|주어진 키가 있는지 확인| +|boolean containsValue(Object value)|주어진 값이 있는지 확인| +|Set> entrySet()|모든 Map.Entry 객체를 Set에 담아 리턴| +|Set keySet()|모든 키를 Set객체에 담아서 리턴| +|V get(Object key)|주어진 키에 있는 값을 리턴| +|boolean isEmpty()| 컬렉션이 비어있는지 조사| +|int Size()|저장되어 있는 전체 객체의 수를 리턴| +|Collection values()|저장된 모든 값을 Collection에 담아서 리턴| +|void clear()|저장된 모든 Map.Entry를 삭제| +|V remove(Object Key)|주어진 키와 일치하는 Map.Entry를 삭제하고 값을 리턴| + +### Reference +- [[Java] 자바 컬렉션 프레임워크(List, Set, Map) 총정리](https://coding-factory.tistory.com/550)