Ch2 계산기 과제 Lv3.

728x90

Lv 3. Enum, 제네릭, 람다 & 스트림을 이해한 계산기 만들기

  • Lv3.java
더보기
더보기
package Lv3;

import java.util.InputMismatchException;
import java.util.Scanner;

public class Lv3 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArithmeticCalculator<Number> calculator = new ArithmeticCalculator<>();
        while (true) {
            int num1 = 0;
            int num2 = 0;
            boolean validInput = false;

            // 양의 정수 입력받기
            while (!validInput) {
                try {
                    System.out.print("양의 정수를 입력해주세요(1/2):");
                    num1 = scanner.nextInt(); // 첫 번째 정수 입력
                    if (num1 < 0) {
                        System.out.println("양의 정수를 입력해야 합니다. 다시 입력해주세요.");
                    } else {
                        validInput = true; // 유효한 입력
                    }
                } catch (InputMismatchException e) {
                    System.out.println("잘못된 입력입니다. 정수를 입력해주세요.");
                    scanner.next();
                }
            }
            validInput = false; // 루프용 boolean 초기화
            while (!validInput) {
                try {
                    System.out.print("양의 정수를 입력해주세요(2/2):");
                    num2 = scanner.nextInt(); // 두 번째 정수 입력
                    if (num2 < 0) {
                        System.out.println("양의 정수를 입력해야 합니다. 다시 입력해주세요.");
                    } else {
                        validInput = true; // 유효한 입력
                    }
                } catch (InputMismatchException e) {
                    System.out.println("잘못된 입력입니다. 정수를 입력해주세요.");
                    scanner.next();
                }
            }
            validInput = false; // 루프용 boolean 초기화
            scanner.nextLine(); // 남아있는 줄바꿈 제거

            // 사칙연산 기호 입력받기
            while (!validInput) {
                System.out.print("사칙연산 기호를 입력해주세요(+-*/):");
                String operatorInput = scanner.nextLine();
                try {
                    OperatorType operator = OperatorType.fromSymbol(operatorInput);
                    calculator.calculate(operator, num1, num2);
                    validInput = true;
                } catch (IllegalArgumentException e) {
                    System.out.println("잘못된 입력입니다. 올바른 사칙연산 기호를 입력해주세요.");
                }
            }

            // 결과 출력 및 저장값 관리
            calculator.getAnswerAndManage();

            // exit 입력시 루프 탈출
            System.out.print("계속 하시겠습니까?(종료:exit):");
            String exit = scanner.nextLine();
            if (exit.equalsIgnoreCase("exit")) { // 대소문자 구분 없이 처리
                System.out.println("프로그램을 종료합니다. 감사합니다!");
                break;
            }
        }
        scanner.close();
    }
}
  • ArithmeticCalculator.java
더보기
더보기
// ArithmeticCalculator.java
package Lv3;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.List;
import java.util.stream.Collectors;

public class ArithmeticCalculator<T extends Number> {
    private T answer;
    private Queue<T> data = new LinkedList<>();

    // 연산 수행
    public void calculate(OperatorType operator, T num1, T num2) {
        double val1 = num1.doubleValue();  // Number 타입을 double로 변환
        double val2 = num2.doubleValue();  // Number 타입을 double로 변환

        try {
            double result = operator.apply(val1, val2); // OperatorType을 통해 연산 수행
            answer = (T) Double.valueOf(result); // 제네릭 타입으로 변환
            if (answer != null) {
                data.add(answer); // 결과를 큐에 추가
            }
        } catch (ArithmeticException e) {
            System.out.println("오류: " + e.getMessage());
            answer = null; // 예외 발생 시 결과를 null로 설정
        }
    }

    // 연산 출력 및 관리
    public void getAnswerAndManage() {
        if (answer == null) {
            System.out.println("계산 결과가 없습니다.");
        } else {
            System.out.println("결과: " + answer);
        }

        System.out.print("기준값을 입력해주세요: ");
        double thresholdValue = new java.util.Scanner(System.in).nextDouble();

        // 조건에 맞는 값들을 오름차순으로 정렬하여 출력
        List<T> greaterResults = data.stream()
                .filter(result -> result.doubleValue() > thresholdValue)
                .sorted(Comparator.comparingDouble(Number::doubleValue))
                .collect(Collectors.toList());

        if (!greaterResults.isEmpty()) {
            System.out.println("조건에 맞는 값들 (오름차순): " + greaterResults);

            // 가장 마지막 값 제거 여부 확인
            System.out.print("가장 마지막 값을 제거하시겠습니까? (y/n): ");
            String input = new java.util.Scanner(System.in).nextLine();
            if (input.equalsIgnoreCase("y")) {
                T lastValue = greaterResults.get(greaterResults.size() - 1);
                data.remove(lastValue);
                System.out.println("제거된 값: " + lastValue);
            }
        } else {
            System.out.println("조건에 맞는 값이 없습니다.");
        }
    }
}
  • OperatorType.java
더보기
더보기
package Lv3;

public enum OperatorType {
    ADD("+") {
        @Override
        public double apply(double x, double y) {
            return x + y;
        }
    },
    SUBTRACT("-") {
        @Override
        public double apply(double x, double y) {
            return x - y;
        }
    },
    MULTIPLY("*") {
        @Override
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/") {
        @Override
        public double apply(double x, double y) {
            if (y == 0) {
                throw new ArithmeticException("0으로 나눌 수 없습니다.");
            }
            return x / y;
        }
    };

    private final String symbol;

    OperatorType(String symbol) {
        this.symbol = symbol;
    }

    public String getSymbol() {
        return symbol;
    }

    public abstract double apply(double x, double y);

    public static OperatorType fromSymbol(String symbol) {
        for (OperatorType op : values()) {
            if (op.getSymbol().equals(symbol.trim())) {
                return op;
            }
        }
        throw new IllegalArgumentException("Invalid operator: " + symbol);
    }

}

Lv3. 과제는 사실 Enum, 제네릭, 람다, 스트림을 이해하는것만 해도 시간이 오래걸려 시작하기도 힘들었습니다. 과제를 끝낸 지금도 아직 제대로 안다고 확신할 수 없는 수준이지만 처음보다는 나아진 것 같습니다.

Enum

Enum이 가장 어려웠습니다. 고정된 상수값을 선언하고 이를 간결하고 타입 안전하게 관리할 수 있도록 도와준다고 하는데, 이 상수를 어떻게 써야할지도 막막하고, 이 외에는 일반 class와 동일하게 사용할 수 있어서 더 헷갈렸습니다. 제가 구현한 enum은 ADD, SUBTRACT, MULTIPLY, DIVIDE를 돌아가며 확인시키고 return 하는데 사용했습니다.

제네릭

num1, num2, answer, Queue 전부 제네릭 타입으로 받게 만들었고, ArithmeticCalculator <T extends Number>로 숫자로 한정했습니다. 계산은 제네릭(Number) 타입으로 하는게 불가능해서 double로 타입을 변환한 후 다시 제네릭 타입으로 변환하여 사용하였습니다.

람다&스트림

람다와 스트림은 Scanner로 입력받은 thresholdValue보다 큰 결과값 들을 출력하는데 사용했습니다. stream으로 Queue에 저장했던 값들을 필터를 씌우고, 오름차순으로 정렬하여 출력했습니다.

728x90
반응형
LIST

'Sparta' 카테고리의 다른 글

스프링 앱 서버 API 설계의 어려움  (0) 2024.12.05
Ch2 키오스크 과제 트러블 슈팅  (0) 2024.11.28
Ch2 계산기 과제 Lv2.  (0) 2024.11.18
Ch2 계산기 과제 Lv1.  (0) 2024.11.18
TIL(Today I Learned)_24.11.04.mon  (0) 2024.11.04