본문 바로가기

[JAVA] 개발

[우아한테크코스] 1주차 문자열 덧셈 계산기

STEP 0 : Application.java

 

프로그램의 진입점 역할을 하며, View와 Controller를 생성하고 실행합니다.

package calculator;

public class Application {
    public static void main(String[] args) {
        CalculatorView view = new CalculatorView();
        CalculatorController controller = new CalculatorController(view);
        controller.processInput();
    }
}

 

 

STEP 1-1 : DelimiterParser.java

 

- Model: DelimiterParser와 Calculator 클래스가 데이터 처리를 담당합니다.
- 구분자를 선별하여, 계산할 값만 추출하는 기능 (+값이 비어 있으면 곧바로, 0 출력.)

package calculator;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DelimiterParser {
    public static String[] parse(String input) {
        // 입력값이 비어("\n") 있으면 숫자 0을 반환하는 메서드
        if (input == null || input.trim().isEmpty()) {
            return new String[] {"0"};
        }
        // 쉼표(,) 또는 콜론(:)을 구분자로 사용
        String delimiter = ",|:";
        
        input = input.replace("\\n", "\n");
        String numbers = input;

        if (input.startsWith("//")) {
            // 사용자 정의 커스텀 구분자 추출 //  "//"와 "\n" 사이에 위치
            Matcher matcher = Pattern.compile("//(.*?)\n(.*)").matcher(input);
            if (matcher.find()) {
                if (matcher.group(1).isEmpty()) {
                    throw new IllegalArgumentException("Delimiter cannot be empty");
                }
                delimiter = Pattern.quote(matcher.group(1)) + "|,|:";
                numbers = matcher.group(2);
            }
        }
        // 구분자로 문자열을 분할하여 반환
        return numbers.split(delimiter);
    }
    
    // public static void main(String[] args) {
    //     // 문자열을 코드 내부에 직접 넣어서 테스트
    //     String input = "//;\n1;2;3";
    //     String[] result = DelimiterParser.parse(input);

    //     int sum = 0;
    //     for (String number : result) {
    //         sum += Integer.parseInt(number);  // 문자열을 숫자로 변환 후 더하기
    //     }
    //     System.out.println("결과: " + sum);  // 결과 출력
    // }
}

 

STEP 1-2 : Calculator.java

 

- Model: DelimiterParser와 Calculator 클래스가 데이터 처리를 담당합니다.
- 숫자 형태로 전환 후 합을 계산

package calculator;

import java.util.Arrays;

public class Calculator {
    public static int calculateSum(String[] numbers) {
        return Arrays.stream(numbers) // 배열을 스트림으로 변환하여, 원소들을 차례로 처리
                     .mapToInt(Calculator::parseNumber) // parseNumber 메서드를 사용하여 문자열을 숫자로 변환
                     .sum();
    }

    private static int parseNumber(String number) {
        try {
            // 공백 제거
            String trimmedNumber = number.trim();
            // 공백인 경우 0으로 처리
            if (trimmedNumber.isEmpty()) {
                return 0;
            }
            int parsedNumber = Integer.parseInt(trimmedNumber);
            if (parsedNumber < 0) {
                throw new IllegalArgumentException("Negative numbers are not allowed: " + number);
            }
            return parsedNumber;
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("잘못된 값을 입력하셨습니다. 애플리케이션은 종료됩니다. 입력값:" + number, e);
        }
    }
}

 

STEP 2 : CalculatorView.java

View: CalculatorView 클래스가 사용자로부터 값을 입력받는다.

package calculator;

import camp.nextstep.edu.missionutils.Console;

public class CalculatorView {
    public String getInput() {
        System.out.println("덧셈할 문자열을 입력해 주세요.");
        String input = Console.readLine();
        
        // 입력값이 null이거나 빈 문자열인 경우 0으로 처리
        if (input == null || input.isEmpty()) {
            return "0";  // 빈 문자열을 0으로 처리
        }
        
        return input;
    }

    public void displayResult(int result) {
        System.out.println("결과 : " + result);
    }

    public void displayError(String message) {
        throw new IllegalArgumentException(message);
    }
}

 

STEP 3 : CalculatorController.java

 

- Controller: CalculatorController 클래스가 Model과 View를 연결하고 전체 로직을 제어한다.

package calculator;

public class CalculatorController {
    private CalculatorView view; // 컨트롤러에서 사용할 View 객체

    public CalculatorController(CalculatorView view) {
        this.view = view; // Application에서 전달받은 View를 저장
    }

    public void processInput() {
        // View를 사용해, 입력을 받는다
        String input = view.getInput();
        
        try {
            String[] numbers = DelimiterParser.parse(input);
            int result = Calculator.calculateSum(numbers);
            // View를 사용해, 결과를 출력
            view.displayResult(result);
        } catch (IllegalArgumentException e) {
            view.displayError(e.getMessage());
        }
    }
}

 

+) DelimiterParserTest.java

//package calculator;
//
//import static org.assertj.core.api.Assertions.assertThat;
//import static org.assertj.core.api.Assertions.assertThatThrownBy;
//
//import org.junit.jupiter.api.Test;
//
//class DelimiterParserTest {
//
//    @Test
//    void parse_숫자_하나() {
//        String input = "1";
//        String[] result = DelimiterParser.parse(input); // 클래스 이름을 사용하여 호출
//        assertThat(result).containsExactly("1");
//    }
//
//    @Test
//    void parse_기본_구분자() {
//        String input = "1,2:3";
//        String[] result = DelimiterParser.parse(input);
//        assertThat(result).containsExactly("1", "2", "3");
//    }
//
//    @Test
//    void parse_커스텀_구분자() {
//        String input = "//;\n1;2;3";
//        String[] result = DelimiterParser.parse(input);
//        assertThat(result).containsExactly("1", "2", "3");
//    }
//
//     @Test
//     void parse_기본_구분자_커스텀_구분자() {
//         String input = "//;\n1;2,3:4";
//         String[] result = DelimiterParser.parse(input);
//         assertThat(result).containsExactly("1", "2", "3", "4");
//     }
//
//    @Test
//    void parse_커스텀_구분자_다양() {
//        String input = "//$%\n1,2,3";
//        String[] result = DelimiterParser.parse(input);
//        assertThat(result).containsExactly("1", "2", "3");
//    }
//
//    @Test
//    void invalidCustomDelimiter_커스텀_구분자_없음() {
//        String input = "//\n1,2:3";
//        assertThatThrownBy(() -> DelimiterParser.parse(input))
//                .isInstanceOf(IllegalArgumentException.class);
//    }
//}

기능 요구 사항

입력한 문자열에서 숫자를 추출하여 더하는 계산기를 구현한다.

  • 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환한다.
    • 예: "" => 0, "1,2" => 3, "1,2,3" => 6, "1,2:3" => 6
  • 앞의 기본 구분자(쉼표, 콜론) 외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 "//"와 "\n" 사이에 위치하는 문자를 커스텀 구분자로 사용한다.
    • 예를 들어 "//;\n1;2;3"과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.
  • 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션은 종료되어야 한다.

입출력 요구 사항

입력

  • 구분자와 양수로 구성된 문자열

출력

  • 덧셈 결과
결과 : 6

실행 결과 예시

덧셈할 문자열을 입력해 주세요.
1,2:3
결과 : 6

프로그래밍 요구 사항

  • JDK 21 버전에서 실행 가능해야 한다.
  • 프로그램 실행의 시작점은 Application의 main()이다.
  • build.gradle 파일은 변경할 수 없으며, 제공된 라이브러리 이외의 외부 라이브러리는 사용하지 않는다.
  • 프로그램 종료 시 System.exit()를 호출하지 않는다.
  • 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 등의 이름을 바꾸거나 이동하지 않는다.
  • 자바 코드 컨벤션을 지키면서 프로그래밍한다.

라이브러리

  • camp.nextstep.edu.missionutils에서 제공하는 Console API를 사용하여 구현해야 한다.
    • 사용자가 입력하는 값은 camp.nextstep.edu.missionutils.Console의 readLine()을 활용한다.