ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,28 @@
+import GameMessage from "./GameMessage.js";
+import { VALID_INPUT_LENGTH } from "./gameConstants.js";
+
+class Validator {
+  static isValidInput(input) {
+    if (!this.isNumber(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_NUMBER);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_CORRECT_LENGTH);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_IS_DUPLICATED);
+    return true;
+  }
+
+  static isNumber(input) {
+    return !Number.isNaN(input);
+  }
+
+  static isValidLength(input) {
+    return input.length === VALID_INPUT_LENGTH;
+  }
+
+  static isDuplicate(input) {
+    return [...new Set(input)].length === VALID_INPUT_LENGTH;
+  }
+}
+
+export default Validator;

리뷰: 3이라는 숫자는 어떤 의미를 가지고 있는 숫자 같은데요,
이러한 숫자가 숫자 그대로 존재하는 것을 흔히 매직넘버라고 부릅니다.
따라서 이러한 숫자는 다음의 이유로 상수화 해주는 것이 좋습니다.

1. 예시로 숫자야구 게임의 숫자갯수가 4로 늘어났다. 그렇다면 모든 파일을 뒤져서 3을 4로 고쳐야한다. (변경에 용이하지 않다.)
2. 처음 온보딩 하는 사람은 이 숫자의 의미를 파악하기 힘들다. 코드 가독성이 줄어든다.
@@ -0,0 +1,28 @@
+import GameMessage from "./GameMessage.js";
+import { VALID_INPUT_LENGTH } from "./gameConstants.js";
+
+class Validator {
+  static isValidInput(input) {
+    if (!this.isNumber(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_NUMBER);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_CORRECT_LENGTH);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_IS_DUPLICATED);
+    return true;
+  }
+
+  static isNumber(input) {
+    return !Number.isNaN(input);
+  }
+
+  static isValidLength(input) {
+    return input.length === VALID_INPUT_LENGTH;
+  }
+
+  static isDuplicate(input) {
+    return [...new Set(input)].length === VALID_INPUT_LENGTH;
+  }
+}
+
+export default Validator;

리뷰: 1. 코드를 다음과 같이 고치면 더 줄어듭니다 ㅎㅎ
```suggestion
        const newArr = [...new Set(input)]
```
2. newArr이라는 상수명이 어떤 의미를 담고 있는 이름인가요? 의미가 없고, 단발성으로 사용되는 측면에서
이렇게 작성해도 될 것 같아요.
```js
isDuplicate(input) {
  if ([...new Set(input)].length !== 3) throw new Error(GameMessage.INVALID_INPUT_IS_DUPLICATED)
  return true;
}
```
@@ -0,0 +1,28 @@
+import GameMessage from "./GameMessage.js";
+import { VALID_INPUT_LENGTH } from "./gameConstants.js";
+
+class Validator {
+  static isValidInput(input) {
+    if (!this.isNumber(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_NUMBER);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_CORRECT_LENGTH);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_IS_DUPLICATED);
+    return true;
+  }
+
+  static isNumber(input) {
+    return !Number.isNaN(input);
+  }
+
+  static isValidLength(input) {
+    return input.length === VALID_INPUT_LENGTH;
+  }
+
+  static isDuplicate(input) {
+    return [...new Set(input)].length === VALID_INPUT_LENGTH;
+  }
+}
+
+export default Validator;

리뷰: 1. 개인적인 견해로는 검증함수에서는 해당 input이 유효한지/안한지(boolean) 평가한 다음,
이 결과에 따라 에러를 던져주는 패턴을 선호합니다.

다시 말하면 에러를 던져주는 부분을 이 함수(is..)를 호출하는 부분으로 넘기는 방식으로 하곤합니다

2. 이게 static method가 아닌 method일 이유가 있나요?
@@ -0,0 +1,28 @@
+import GameMessage from "./GameMessage.js";
+import { VALID_INPUT_LENGTH } from "./gameConstants.js";
+
+class Validator {
+  static isValidInput(input) {
+    if (!this.isNumber(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_NUMBER);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_CORRECT_LENGTH);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_IS_DUPLICATED);
+    return true;
+  }
+
+  static isNumber(input) {
+    return !Number.isNaN(input);
+  }
+
+  static isValidLength(input) {
+    return input.length === VALID_INPUT_LENGTH;
+  }
+
+  static isDuplicate(input) {
+    return [...new Set(input)].length === VALID_INPUT_LENGTH;
+  }
+}
+
+export default Validator;

리뷰: 필요없는 주석은 지우면 좋겠습니다 !
@@ -0,0 +1,28 @@
+import GameMessage from "./GameMessage.js";
+import { VALID_INPUT_LENGTH } from "./gameConstants.js";
+
+class Validator {
+  static isValidInput(input) {
+    if (!this.isNumber(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_NUMBER);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_NOT_A_CORRECT_LENGTH);
+    if (!this.isValidLength(input))
+      throw new Error(GameMessage.INVALID_INPUT_IS_DUPLICATED);
+    return true;
+  }
+
+  static isNumber(input) {
+    return !Number.isNaN(input);
+  }
+
+  static isValidLength(input) {
+    return input.length === VALID_INPUT_LENGTH;
+  }
+
+  static isDuplicate(input) {
+    return [...new Set(input)].length === VALID_INPUT_LENGTH;
+  }
+}
+
+export default Validator;

리뷰: boolean을 리턴할 때는 메서드의 prefix에 is, has를 붙여주는 것이 관례입니다ㅎ_ㅎ
@@ -0,0 +1,49 @@
+import { Random } from "@woowacourse/mission-utils";
+import {
+  VALID_INPUT_LENGTH,
+  MIN_RANDOM_NUMBER,
+  MAX_RANDOM_NUMBER,
+} from "./gameConstants.js";
+
+class Computer {
+  #solution;
+
+  seeSolution() {
+    return this.#solution;
+  }
+
+  makeSolution() {
+    const computer = [];
+    while (computer.length < VALID_INPUT_LENGTH) {
+      const number = Random.pickNumberInRange(
+        MIN_RANDOM_NUMBER,
+        MAX_RANDOM_NUMBER
+      );
+      if (!computer.includes(number)) {
+        computer.push(number);
+      }
+    }
+    this.#solution = computer;
+  }
+
+  assessUserInput(input) {
+    let strike = 0;
+    let ball = 0;
+    const userInput = input.split("").map(Number);
+    userInput.forEach((item, index) => {
+      if (
+        this.#solution.indexOf(item) === index &&
+        this.#solution.includes(item)
+      )
+        strike += 1;
+      else if (
+        this.#solution.indexOf(item) !== index &&
+        this.#solution.includes(item)
+      )
+        ball += 1;
+    });
+    return { strike, ball };
+  }
+}
+
+export default Computer;

리뷰: 어떤 구문에는 세미콜론이 있고, 어떤 구문에는 세미콜론이 있지 않네요.

둘 중 하나만 하시는 걸 추천드리고, 강제하고 싶다면 prettier등을 이용해보세요.
@@ -0,0 +1,49 @@
+import { Random } from "@woowacourse/mission-utils";
+import {
+  VALID_INPUT_LENGTH,
+  MIN_RANDOM_NUMBER,
+  MAX_RANDOM_NUMBER,
+} from "./gameConstants.js";
+
+class Computer {
+  #solution;
+
+  seeSolution() {
+    return this.#solution;
+  }
+
+  makeSolution() {
+    const computer = [];
+    while (computer.length < VALID_INPUT_LENGTH) {
+      const number = Random.pickNumberInRange(
+        MIN_RANDOM_NUMBER,
+        MAX_RANDOM_NUMBER
+      );
+      if (!computer.includes(number)) {
+        computer.push(number);
+      }
+    }
+    this.#solution = computer;
+  }
+
+  assessUserInput(input) {
+    let strike = 0;
+    let ball = 0;
+    const userInput = input.split("").map(Number);
+    userInput.forEach((item, index) => {
+      if (
+        this.#solution.indexOf(item) === index &&
+        this.#solution.includes(item)
+      )
+        strike += 1;
+      else if (
+        this.#solution.indexOf(item) !== index &&
+        this.#solution.includes(item)
+      )
+        ball += 1;
+    });
+    return { strike, ball };
+  }
+}
+
+export default Computer;

리뷰: 1. 이렇게도 됩니다.
```suggestion
        const userInput = input.split("").map(Number);
```
2. 배열이면.. s가 붙으면 좋지 않을까요?
@@ -0,0 +1,49 @@
+import { Random } from "@woowacourse/mission-utils";
+import {
+  VALID_INPUT_LENGTH,
+  MIN_RANDOM_NUMBER,
+  MAX_RANDOM_NUMBER,
+} from "./gameConstants.js";
+
+class Computer {
+  #solution;
+
+  seeSolution() {
+    return this.#solution;
+  }
+
+  makeSolution() {
+    const computer = [];
+    while (computer.length < VALID_INPUT_LENGTH) {
+      const number = Random.pickNumberInRange(
+        MIN_RANDOM_NUMBER,
+        MAX_RANDOM_NUMBER
+      );
+      if (!computer.includes(number)) {
+        computer.push(number);
+      }
+    }
+    this.#solution = computer;
+  }
+
+  assessUserInput(input) {
+    let strike = 0;
+    let ball = 0;
+    const userInput = input.split("").map(Number);
+    userInput.forEach((item, index) => {
+      if (
+        this.#solution.indexOf(item) === index &&
+        this.#solution.includes(item)
+      )
+        strike += 1;
+      else if (
+        this.#solution.indexOf(item) !== index &&
+        this.#solution.includes(item)
+      )
+        ball += 1;
+    });
+    return { strike, ball };
+  }
+}
+
+export default Computer;

리뷰: reduce를 써서도 구현할 수 있겠네요
```js
const strikeAndBall = userInput.reduce((acc, cur) => {
  if ((this.#solution.indexOf(item) === index) && this.#solution.includes(item)) return { ...acc, strike: acc.strike + 1 }
if ((this.#solution.indexOf(item) !== index) && this.#solution.includes(item)) return { ...acc, ball:acc.ball + 1}
return acc;
}, { strike: 0, ball: 0})
```
@@ -0,0 +1,15 @@
+{
+  "arrowParens": "always",
+  "bracketSpacing": true,
+  "jsxBracketSameLine": false,
+  "jsxSingleQuote": false,
+  "printWidth": 80,
+  "proseWrap": "always",
+  "quoteProps": "as-needed",
+  "semi": true,
+  "singleQuote": false,
+  "tabWidth": 2,
+  "trailingComma": "es5",
+  "useTabs": false,
+  "endOfLine": "auto"
+}
\ No newline at end of file

리뷰: 코드를 보면 prettier가 적용되어있지 않은데, 확인한번 해보세용
@@ -0,0 +1,49 @@
+import { Random } from "@woowacourse/mission-utils";
+import {
+  VALID_INPUT_LENGTH,
+  MIN_RANDOM_NUMBER,
+  MAX_RANDOM_NUMBER,
+} from "./gameConstants.js";
+
+class Computer {
+  #solution;
+
+  seeSolution() {
+    return this.#solution;
+  }
+
+  makeSolution() {
+    const computer = [];
+    while (computer.length < VALID_INPUT_LENGTH) {
+      const number = Random.pickNumberInRange(
+        MIN_RANDOM_NUMBER,
+        MAX_RANDOM_NUMBER
+      );
+      if (!computer.includes(number)) {
+        computer.push(number);
+      }
+    }
+    this.#solution = computer;
+  }
+
+  assessUserInput(input) {
+    let strike = 0;
+    let ball = 0;
+    const userInput = input.split("").map(Number);
+    userInput.forEach((item, index) => {
+      if (
+        this.#solution.indexOf(item) === index &&
+        this.#solution.includes(item)
+      )
+        strike += 1;
+      else if (
+        this.#solution.indexOf(item) !== index &&
+        this.#solution.includes(item)
+      )
+        ball += 1;
+    });
+    return { strike, ball };
+  }
+}
+
+export default Computer;

리뷰: 이걸 리턴하는 이유가 뭔가요 ?
@@ -1,5 +1,62 @@
+import { Console } from "@woowacourse/mission-utils";
+import User from "./User.js";
+import Computer from "./Computer.js";
+import Validator from "./Validator.js";
+import GameMessage from "./GameMessage.js";
+import { RETRY_RESPONSE, FULL_STRIKE } from "./gameConstants.js";
+
 class App {
-  async play() {}
+  constructor() {
+    this.user = new User();
+    this.computer = new Computer();
+  }
+
+  async play() {
+    this.computer.makeSolution();
+    Console.print(GameMessage.START_MESSAGE);
+    await this.mainLogic();
+  }
+
+  async mainLogic() {
+    await this.setUserInput();
+    this.printStrikeBall();
+    if (
+      this.computer.assessUserInput(this.user.getNumber()).strike !==
+      FULL_STRIKE
+    )
+      await this.mainLogic();
+    else {
+      const replayResponse = await Console.readLineAsync(
+        "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."
+      );
+      if (parseInt(replayResponse, 10) === RETRY_RESPONSE) {
+        this.computer.makeSolution();
+        this.mainLogic();
+      }
+    }
+  }
+
+  async setUserInput() {
+    const input = await Console.readLineAsync("숫자를 입력해주세요 : ");
+    if (Validator.isValidInput(input)) {
+      this.user.setNumber(input);
+    }
+  }
+
+  printStrikeBall() {
+    const { strike, ball } = this.computer.assessUserInput(
+      this.user.getNumber()
+    );
+    if (strike === 0 && ball === 0) {
+      Console.print(GameMessage.NOTHING_MESSAGE);
+    } else if (strike > 0 && ball > 0) {
+      Console.print(`${strike}볼 ${ball}스트라이크`);
+    } else if (strike === FULL_STRIKE) {
+      Console.print(GameMessage.SOLVED_MESSAGE);
+    } else {
+      Console.print(`${strike}스트라이크 ${ball}볼`);
+    }
+  }
 }
 
 export default App;

리뷰: indent가..
@@ -1,5 +1,62 @@
+import { Console } from "@woowacourse/mission-utils";
+import User from "./User.js";
+import Computer from "./Computer.js";
+import Validator from "./Validator.js";
+import GameMessage from "./GameMessage.js";
+import { RETRY_RESPONSE, FULL_STRIKE } from "./gameConstants.js";
+
 class App {
-  async play() {}
+  constructor() {
+    this.user = new User();
+    this.computer = new Computer();
+  }
+
+  async play() {
+    this.computer.makeSolution();
+    Console.print(GameMessage.START_MESSAGE);
+    await this.mainLogic();
+  }
+
+  async mainLogic() {
+    await this.setUserInput();
+    this.printStrikeBall();
+    if (
+      this.computer.assessUserInput(this.user.getNumber()).strike !==
+      FULL_STRIKE
+    )
+      await this.mainLogic();
+    else {
+      const replayResponse = await Console.readLineAsync(
+        "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."
+      );
+      if (parseInt(replayResponse, 10) === RETRY_RESPONSE) {
+        this.computer.makeSolution();
+        this.mainLogic();
+      }
+    }
+  }
+
+  async setUserInput() {
+    const input = await Console.readLineAsync("숫자를 입력해주세요 : ");
+    if (Validator.isValidInput(input)) {
+      this.user.setNumber(input);
+    }
+  }
+
+  printStrikeBall() {
+    const { strike, ball } = this.computer.assessUserInput(
+      this.user.getNumber()
+    );
+    if (strike === 0 && ball === 0) {
+      Console.print(GameMessage.NOTHING_MESSAGE);
+    } else if (strike > 0 && ball > 0) {
+      Console.print(`${strike}볼 ${ball}스트라이크`);
+    } else if (strike === FULL_STRIKE) {
+      Console.print(GameMessage.SOLVED_MESSAGE);
+    } else {
+      Console.print(`${strike}스트라이크 ${ball}볼`);
+    }
+  }
 }
 
 export default App;

리뷰: 매직넘버가 살아이있네용
@@ -1,5 +1,62 @@
+import { Console } from "@woowacourse/mission-utils";
+import User from "./User.js";
+import Computer from "./Computer.js";
+import Validator from "./Validator.js";
+import GameMessage from "./GameMessage.js";
+import { RETRY_RESPONSE, FULL_STRIKE } from "./gameConstants.js";
+
 class App {
-  async play() {}
+  constructor() {
+    this.user = new User();
+    this.computer = new Computer();
+  }
+
+  async play() {
+    this.computer.makeSolution();
+    Console.print(GameMessage.START_MESSAGE);
+    await this.mainLogic();
+  }
+
+  async mainLogic() {
+    await this.setUserInput();
+    this.printStrikeBall();
+    if (
+      this.computer.assessUserInput(this.user.getNumber()).strike !==
+      FULL_STRIKE
+    )
+      await this.mainLogic();
+    else {
+      const replayResponse = await Console.readLineAsync(
+        "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."
+      );
+      if (parseInt(replayResponse, 10) === RETRY_RESPONSE) {
+        this.computer.makeSolution();
+        this.mainLogic();
+      }
+    }
+  }
+
+  async setUserInput() {
+    const input = await Console.readLineAsync("숫자를 입력해주세요 : ");
+    if (Validator.isValidInput(input)) {
+      this.user.setNumber(input);
+    }
+  }
+
+  printStrikeBall() {
+    const { strike, ball } = this.computer.assessUserInput(
+      this.user.getNumber()
+    );
+    if (strike === 0 && ball === 0) {
+      Console.print(GameMessage.NOTHING_MESSAGE);
+    } else if (strike > 0 && ball > 0) {
+      Console.print(`${strike}볼 ${ball}스트라이크`);
+    } else if (strike === FULL_STRIKE) {
+      Console.print(GameMessage.SOLVED_MESSAGE);
+    } else {
+      Console.print(`${strike}스트라이크 ${ball}볼`);
+    }
+  }
 }
 
 export default App;

리뷰: 이렇게 eslint 규칙을 무시할거면 eslint를 왜 사용하시나요?
@@ -1,20 +1,36 @@
 package model;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class Lotto {
 
-    private List<String> lottoNumbers;
+    private List<LottoNo> lottoNumbers;
 
-    public Lotto(List<String> lottoNumbers) {
+    public Lotto(List<LottoNo> lottoNumbers) {
         this.lottoNumbers = lottoNumbers;
     }
 
-    public int getCorrectNumberCount(List<String> winningNumber) {
-        return (int) winningNumber.stream().filter((x) -> lottoNumbers.contains(x)).count();
+    public Lotto(String[] lottoNumbers) {
+        this.lottoNumbers = new ArrayList<>();
+        for (int i = 0; i < lottoNumbers.length; i++)
+            this.lottoNumbers.add(new LottoNo(Integer.parseInt(lottoNumbers[i])));
     }
 
     public String showLotto() {
-        return lottoNumbers.toString();
+        List<String> lotto = new ArrayList<>();
+
+        for (LottoNo lottoNo : lottoNumbers)
+            lotto.add(lottoNo.getStringNumber());
+
+        return lotto.toString();
+    }
+
+    public int getCorrectCount(List<String> winningNumbers) {
+        return (int) lottoNumbers.stream().filter((x) -> winningNumbers.contains(x.getStringNumber())).count();
+    }
+
+    public boolean isContain(String stringNumber) {
+        return (int)lottoNumbers.stream().filter(x -> x.getStringNumber().equals(stringNumber)).count() != 0;
     }
 }

리뷰: 로또 번호를 Set 으로 구현하는 것과 List 로 구현하는 것을 비교해 보았을 때 어떤 장단점이 있을까요? 여기서는 어떤 자료구조가 어울릴까요?
@@ -1,20 +1,36 @@
 package model;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class Lotto {
 
-    private List<String> lottoNumbers;
+    private List<LottoNo> lottoNumbers;
 
-    public Lotto(List<String> lottoNumbers) {
+    public Lotto(List<LottoNo> lottoNumbers) {
         this.lottoNumbers = lottoNumbers;
     }
 
-    public int getCorrectNumberCount(List<String> winningNumber) {
-        return (int) winningNumber.stream().filter((x) -> lottoNumbers.contains(x)).count();
+    public Lotto(String[] lottoNumbers) {
+        this.lottoNumbers = new ArrayList<>();
+        for (int i = 0; i < lottoNumbers.length; i++)
+            this.lottoNumbers.add(new LottoNo(Integer.parseInt(lottoNumbers[i])));
     }
 
     public String showLotto() {
-        return lottoNumbers.toString();
+        List<String> lotto = new ArrayList<>();
+
+        for (LottoNo lottoNo : lottoNumbers)
+            lotto.add(lottoNo.getStringNumber());
+
+        return lotto.toString();
+    }
+
+    public int getCorrectCount(List<String> winningNumbers) {
+        return (int) lottoNumbers.stream().filter((x) -> winningNumbers.contains(x.getStringNumber())).count();
+    }
+
+    public boolean isContain(String stringNumber) {
+        return (int)lottoNumbers.stream().filter(x -> x.getStringNumber().equals(stringNumber)).count() != 0;
     }
 }

리뷰: 한줄이더라도 괄호를 붙여주는걸 컨벤션으로 합시다. 
이것이 간결하더라도 읽는 사람 입장으로 코드를 보면
당연히 있어야할 곳에 무언가가 빠지게 되면 가독성이 저하됩니다. (책 읽을 때와 비슷)
그리고 생성자에서 뭔가 많은 일을 해주는게 아쉽네요
@@ -1,20 +1,36 @@
 package model;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class Lotto {
 
-    private List<String> lottoNumbers;
+    private List<LottoNo> lottoNumbers;
 
-    public Lotto(List<String> lottoNumbers) {
+    public Lotto(List<LottoNo> lottoNumbers) {
         this.lottoNumbers = lottoNumbers;
     }
 
-    public int getCorrectNumberCount(List<String> winningNumber) {
-        return (int) winningNumber.stream().filter((x) -> lottoNumbers.contains(x)).count();
+    public Lotto(String[] lottoNumbers) {
+        this.lottoNumbers = new ArrayList<>();
+        for (int i = 0; i < lottoNumbers.length; i++)
+            this.lottoNumbers.add(new LottoNo(Integer.parseInt(lottoNumbers[i])));
     }
 
     public String showLotto() {
-        return lottoNumbers.toString();
+        List<String> lotto = new ArrayList<>();
+
+        for (LottoNo lottoNo : lottoNumbers)
+            lotto.add(lottoNo.getStringNumber());
+
+        return lotto.toString();
+    }
+
+    public int getCorrectCount(List<String> winningNumbers) {
+        return (int) lottoNumbers.stream().filter((x) -> winningNumbers.contains(x.getStringNumber())).count();
+    }
+
+    public boolean isContain(String stringNumber) {
+        return (int)lottoNumbers.stream().filter(x -> x.getStringNumber().equals(stringNumber)).count() != 0;
     }
 }

리뷰: boolean을 int 로 변환해주는 이유는 뭔가요?
@@ -1,20 +1,36 @@
 package model;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class Lotto {
 
-    private List<String> lottoNumbers;
+    private List<LottoNo> lottoNumbers;
 
-    public Lotto(List<String> lottoNumbers) {
+    public Lotto(List<LottoNo> lottoNumbers) {
         this.lottoNumbers = lottoNumbers;
     }
 
-    public int getCorrectNumberCount(List<String> winningNumber) {
-        return (int) winningNumber.stream().filter((x) -> lottoNumbers.contains(x)).count();
+    public Lotto(String[] lottoNumbers) {
+        this.lottoNumbers = new ArrayList<>();
+        for (int i = 0; i < lottoNumbers.length; i++)
+            this.lottoNumbers.add(new LottoNo(Integer.parseInt(lottoNumbers[i])));
     }
 
     public String showLotto() {
-        return lottoNumbers.toString();
+        List<String> lotto = new ArrayList<>();
+
+        for (LottoNo lottoNo : lottoNumbers)
+            lotto.add(lottoNo.getStringNumber());
+
+        return lotto.toString();
+    }
+
+    public int getCorrectCount(List<String> winningNumbers) {
+        return (int) lottoNumbers.stream().filter((x) -> winningNumbers.contains(x.getStringNumber())).count();
+    }
+
+    public boolean isContain(String stringNumber) {
+        return (int)lottoNumbers.stream().filter(x -> x.getStringNumber().equals(stringNumber)).count() != 0;
     }
 }

리뷰: 이 부분 좀 더 개선해보세요
@@ -1,20 +1,36 @@
 package model;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class Lotto {
 
-    private List<String> lottoNumbers;
+    private List<LottoNo> lottoNumbers;
 
-    public Lotto(List<String> lottoNumbers) {
+    public Lotto(List<LottoNo> lottoNumbers) {
         this.lottoNumbers = lottoNumbers;
     }
 
-    public int getCorrectNumberCount(List<String> winningNumber) {
-        return (int) winningNumber.stream().filter((x) -> lottoNumbers.contains(x)).count();
+    public Lotto(String[] lottoNumbers) {
+        this.lottoNumbers = new ArrayList<>();
+        for (int i = 0; i < lottoNumbers.length; i++)
+            this.lottoNumbers.add(new LottoNo(Integer.parseInt(lottoNumbers[i])));
     }
 
     public String showLotto() {
-        return lottoNumbers.toString();
+        List<String> lotto = new ArrayList<>();
+
+        for (LottoNo lottoNo : lottoNumbers)
+            lotto.add(lottoNo.getStringNumber());
+
+        return lotto.toString();
+    }
+
+    public int getCorrectCount(List<String> winningNumbers) {
+        return (int) lottoNumbers.stream().filter((x) -> winningNumbers.contains(x.getStringNumber())).count();
+    }
+
+    public boolean isContain(String stringNumber) {
+        return (int)lottoNumbers.stream().filter(x -> x.getStringNumber().equals(stringNumber)).count() != 0;
     }
 }

리뷰: x 를 좀 더 의미있는 변수이름으로 지었으면 좋았을 것 같습니다.
그리고 메소드 체이닝 방식에서는 길이가 길어지면 IDE에서 한눈에 확인하기 힘드니까
가독성을 위해 엔터로 라인정리를 어느정도 해주는 것이 좋습니다.
이를 위한 컨벤션도 intellij code style 에서 자동정렬 설정할 수 있긴 합니다(저는 사용중)