요구 사항
- ⬜ 현재 사칙연산 계산기는 (➕,➖,✖️,➗) 이렇게 총 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 |