Develope Story

2019-05-09 [java-study] 문자열 덧셈 계산기 스터디

|

문자열 덧셈 계산기

요구사항

  • 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환 (예: “” => 0, “1,2” => 3, “1,2,3” => 6, “1,2:3” => 6)

  • 앞의 기본 구분자(쉼표, 콜론)외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 “//”와 “\n” 사이에 위치하는 문자를 커스텀 구분자로 사용한다. 예를 들어 “//;\n1;2;3”과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.

  • 문자열 계산기에 숫자 이외의 값 또는 음수를 전달하는 경우 RuntimeException 예외를 throw한다

프로그래밍 요구사항

  • indent(들여쓰기) depth를 2단계에서 1단계로 줄여라.
    • depth의 경우 if문을 사용하는 경우 1단계의 depth가 증가한다. if문 안에 while문을 사용한다면 depth가 2단계가 된다.
  • 메소드의 크기가 최대 10라인을 넘지 않도록 구현한다.
    • method가 한 가지 일만 하도록 최대한 작게 만들어라.
  • else를 사용하지 마라.

요구사항 힌트

  • 빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다.(예 : “” => 0, null => 0)

  • 숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.(예 : “1”)

  • 숫자 두개를 컴마(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다.(예 : “1,2”)

  • 구분자를 컴마(,) 이외에 콜론(:)을 사용할 수 있다. (예 : “1,2:3” => 6)

  • “//”와 “\n” 문자 사이에 커스텀 구분자를 지정할 수 있다. (예 : “//;\n1;2;3” => 6)

  • 음수를 전달할 경우 RuntimeException 예외가 발생해야 한다. (예 : “-1,2,3”)

목표

  • 리팩토링 시간을 줄이자! (정해진 시간안에 구현)
  • Test -> 구현 순서
  • stream or 람다식 사용

공부한 내용

Pattern, Matcher 클래스

Pattern p = Pattern.compile('정규식');
Matcher matcher = p.matcher("문자열");
  • find()
    • Pattern에 일치하는 텍스트가 발견 되면 true
  • group()
    • 패턴과 일치하는 텍스트를 반환

정규식

표현식 설명
^ 문자열의 시작
$ 문자열의 종료
. 임의의 한 문자 (줄바꿈 제외)
[…] [] 사이에 있는 문자 혹은 문자집합 (ex A-Z)
[^…] [] 사이에 있는 문자 혹은 문자집합 제외
* 앞문자가 문자열일 많을수도 없을수도
+ 앞 문자가 하나 이상
? 앞 문자가 없거나 하나
{} 횟수 또는 범위
\d [0-9]

더 많은 표현 : https://jamesdreaming.tistory.com/179

자주 사용하는 거

  1. 숫자만 : ^[0-9]*$

  2. 영문자만 : ^[a-zA-Z]*$

  3. 한글만 : ^[가-힣]*$

  4. 영어 & 숫자만 : ^[a-zA-Z0-9]*$

  5. E-Mail : ^[a-zA-Z0-9]+@[a-zA-Z0-9]+$

  6. 휴대폰 : ^01(?:0|1|[6-9]) - (?:\d{3}|\d{4}) - \d{4}$

  7. 일반전화 : ^\d{2.3} - \d{3,4} - \d{4}$

  8. 주민등록번호 : \d{6} \- [1-4]\d{6}

  9. IP 주소 : ([0-9]{1,3}) \. ([0-9]{1,3}) \. ([0-9]{1,3}) \. ([0-9]{1,3})

"//;\n1;2;3"

Matcher matcher = Pattern.compile("//(.)\n(.*)").matcher(string);

=> //\n 사이의 문자가 식의 구분자

matcher.group(2), matcher.group(1) //group(2)는 1;2;3 group(1)은 ;

Stream

  • mapToInt() : 객체 스트림을 기본 타입 스트림으로 변환 (Stream -> IntStream)

  • allMatch() : 모든 파라미터가 조건에 중촉되는지

String[] str = {"1", "2", "3"};
Arrays.stream(str).mapToInt(num -> Integer.parseInt(num)).allMatch(num -> num > 0);

assertThat

=> 가독성 UP

  • isEqualTo = 동등

assertThat(stringAddCalculator.calculate(null)).isEqualTo(0);

  • contains

  • startWith

  • 더 많은 정보 : https://joel-costigliola.github.io/assertj/

##리뷰 받은 내용

  • 변수를 줄여쓰지 않는다.

StringAddCalculator cal;

  • assertThat() 사용하기 (참고 https://joel-costigliola.github.io/assertj/ )

  • java Stream stream = Arrays.stream(str); stream.mapToInt(num -> Integer.parseInt(num)).allMatch(num -> num > 0);

    stream을 선언하지 않고 한줄에 끝낼수있다.

  • 무조건 stream을 사용하지말고 장점이 있는 경우에만 사용 => 이번엔 stream을 사용해 보고싶었음 다음부턴 효율적으로 적용

  • Test 작성 -> Test Fail -> Test 통과할만큼의 간단한 구현 -> 중복제거 리팩토링 -> 다른 요구사항 test 작성 -> … 무한반복

  • Scanner 생성 비용이 높아 메소드에서 생성하는 것보단 매개변수로 받는게 좋음 => threadSafe문제

  • 변수명에 자료형 이름이 오지 않는다.

힘든점

  • 정규식 표현을 읽기 힘들었다.
    • 정규식 사용 이유 : 코딩 시간절약, 특정 문자나 문자열 검색등등
    • 단점 : 가독성 떨어짐.
  • 저번보다 리팩토링 시간을 줄였음.
  • test 작성 -> 구현 -> 리팩토링 순서
  • 추가 요구 사항 (선택)
    • 1번 (positive 객체 사용) => stream 사용할 아이디어가 생각이안남
    • 2번 (Inteface를 사용하여 Splitter 구현) => interface 사용시 오버라이딩 때문에 static 메소드 사용할 수 없어서 더 복잡해졌음.
    • 3번 (람다식 사용) => 이번 과제는 람다식 (Stream) 중심으로 구현

소스 코드 : https://github.com/sproutt/spring-study-lotto/pull/11/files

Comments