본문 바로가기

JAVA

[Java] Lv_3 계산기 문제

요구 사항

  • ⬜ 현재 사칙연산 계산기는 (➕,➖,✖️,➗) 이렇게 총 4가지 연산 타입으로 구성되어 있습니다.
    • ⬜  Enum 타입을 활용하여 연산자 타입에 대한 정보를 관리하고 이를 사칙연산 계산기 ArithmeticCalculator 클래스에 활용 해봅니다. 
  • ⬜ 실수, 즉 double 타입의 값을 전달 받아도 연산이 수행하도록 만들기
    • ⬜ 키워드 : 제네릭
      • ⬜  단순히, 기존의 Int 타입을 double 타입으로 바꾸는 게 아닌 점에 주의하세요!
    • ⬜  지금까지는 ArithmeticCalculator, 즉 사칙연산 계산기는 양의 정수(0 포함)를 매개변수로 전달받아 연산을 수행
    • ⬜ 피연산자를 여러 타입으로 받을 수 있도록 기능을 확장
      • ⬜ ArithmeticCalculator 클래스의 연산 메서드(calculate)
    • ⬜  위 요구사항을 만족할 수 있도록 ArithmeticCalculator 클래스를 수정합니다. (제네릭)
      • ⬜ 추가적으로 수정이 필요한 다른 클래스나 메서드가 있다면 같이 수정 해주세요.
  • ⬜ 저장된 연산 결과들 중 Scanner로 입력받은 값보다 큰 결과값 들을 출력
    • ⬜ ArithmeticCalculator 클래스에 위 요구사항을 만족하는 조회 메서드를 구현합니다.
    • ⬜  단, 해당 메서드를 구현할 때 Lambda & Stream을 활용하여 구현합니다.

 

 


 

 

문제 풀이

더보기

App

package lv3;

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

public class App {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Data data = new Data();

        while (true) {
            try {
            System.out.print("1. 계산하기 2.조회하기 3.삭제하기 4.종료하기 : ");
            int option = scanner.nextInt();
            switch(option) {
                case 1: {
                    System.out.print("첫 번째 숫자를 입력해주세요 : ");
                    double firstNum = scanner.nextDouble();

                    System.out.print("사칙 연산 기호를 입력해주세요 : ");
                    char operator = scanner.next().charAt(0);

                    System.out.print("두 번째 숫자를 입력해주세요 : ");
                    double secondNum = scanner.nextDouble();
                    scanner.nextLine();

                    if (firstNum < 0 || secondNum < 0) {
                        System.out.println("양의 정수만 입력하세요");
                    } else {
                        ArithmeticCalculator<Double> calculator = new ArithmeticCalculator<>(firstNum, operator, secondNum);
                        data.setData(calculator.calculate());
                    }
                    break;
                }
                case 2: {
                    System.out.print("몇 이상의 저장값을 조회하시겠습니까? ");
                    data.getFormatData(scanner.nextInt());
                    scanner.nextLine();
                    break;
                }
                case 3: {
                    data.deleteFirstData();
                    data.getData();
                    break;
                }
                case 4: {
                    return;
                }
                default: {
                    System.out.println("올바른 메뉴를 선택해주세요.");
                }
            }
            } catch (InputMismatchException e) {
                System.out.println("숫자만 입력해주세요!");
                scanner.nextLine();
            }
        }
    }
}

switch~case 문을 통해 초기 선택지(계산, 조회, 삭제, 종료)를 추가하였다.

정수형과 실수형을 둘 다 받으려면, 정수형보다 큰 실수형 타입으로 피연산자를 받았다.

 

 

 

더보기

ArithmeticCalculator

package lv3;

import java.util.Optional;

public class ArithmeticCalculator <T extends Number> {
    // 속성
    Operator op;
    T a;
    T a1;

    // 생성자
    public ArithmeticCalculator(T firstNum, char operator, T secondNum) {
        switch(operator) {
            case '+': {
                op = Operator.PLUS;
                break;
            }
            case '-': {
                op = Operator.MINUS;
                break;
            }
            case '*': {
                op = Operator.MULTIPLY;
                break;
            }
            case '/': {
                op = Operator.DIVIDE;
            }
            default: {
                System.out.println("잘못된 연산자입니다.");
                op = Operator.NONE;
            }
        }
        a = firstNum;
        a1 = secondNum;
    }

    // 기능
    public Optional<Double> calculate() {
        double result;
        switch(op) {
            case Operator.PLUS: {
                result = a.doubleValue() + a1.doubleValue();
                System.out.println(a.doubleValue() + " + " + a1.doubleValue() + " = " + result);
                return Optional.of(result);
            }
            case Operator.MINUS: {
                result = a.doubleValue() - a1.doubleValue();
                System.out.println(a.doubleValue() + " - " + a1.doubleValue() + " = " + result);
                return Optional.of(result);
            }
            case Operator.MULTIPLY: {
                result = a.doubleValue() * a1.doubleValue();
                System.out.println(a.doubleValue() + " * " + a1.doubleValue() + " = " + result);
                return Optional.of(result);
            }
            case Operator.DIVIDE: {
                if(a1.doubleValue() == 0) {
                    System.out.println("0으로 나눌 수 없습니다.");
                    return Optional.empty();
                }
                result = a.doubleValue() / a1.doubleValue();
                System.out.println(a.doubleValue() + " / " + a1.doubleValue() + " = " + result);
                return Optional.of(result);
            }
            default: {
                return Optional.empty();
            }
        }
    }
}

T extends Number : 여러 타입으로 받을 수 있게 제네릭으로 설정하였다. 그 중에서 숫자 클래스들만 받을 수 있게 타입을 제한하였다.

  • Integer, Double, Float, Long 같은 숫자 관련 클래스는 모드 Number 부모 클래스를 상속받는다.
  • 제한하는 이유 : calculate 메서드에서 T 타입으로 선언된 a와 a1 변수를 사칙연산 할 수 있게 된다.

Optional<Double>을 사용하는 이유 :

  • Optional을 사용하지 않으면, 반환값이 없을 때 null을 반환해야한다. null을 반환하게 되면, NullpointException 오류가 발생할 수 있으므로, Optional을 사용하여, 예방할 수 있다.

 

 

더보기

Operator

package lv3;

public enum Operator {
    PLUS,
    MINUS,
    MULTIPLY,
    DIVIDE,
    NONE;
}

NONE : 연산자가 잘못 들어온 경우

 

 

 

더보기

Data

package lv3;

import java.util.ArrayDeque;
import java.util.Optional;
import java.util.Queue;

public class Data {
    // 속성
    final private Queue<Optional<Double>> resultList = new ArrayDeque<>();

    // 생성자

    // 기능
    public void setData(Optional<Double> data) {
        data.ifPresent(resultList::add);
    }

    public void getData() {
        System.out.println(resultList);
    }

    public void deleteFirstData() {
        if (!resultList.isEmpty()) {
        	resultList.remove();
    	}
    }

    public void getFormatData(int data) {
        System.out.println(resultList.stream()
                .filter(num -> num.isPresent() && num.get() >= data)
                .map(num -> num.get())
                .toList());
    }
}

컬렉션 Queue에서 타입을 Optional<Double>로 받고 있다.

getFormatData에서 컬렉션 값을 꺼내오려면 한 번은 Optional 안에 있는 값을 꺼내야한다. 컬렉션이 Optional<Double> 타입이기 때문이다.

  • .map(num -> num.get()) : Optional 안에 있던 값을 꺼낸다.
  • isPresent()를 통해 값이 있는 경우만 가져왔기 때문에 안전하게 꺼내올 수 있다.

'JAVA' 카테고리의 다른 글

[Java] Lv_1 키오스크  (0) 2025.04.24
[Java] 예외 처리  (0) 2025.04.23
[Java] 다이아몬드 상속  (0) 2025.04.19
[Java] toString()  (0) 2025.04.18
[Java] Lv_2 계산기 프로젝트  (0) 2025.04.18