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 |