💡자바 콘솔로 간단한 사칙연산 계산기 만들기2 - 추가 기능
Generic 타입으로 변경하여 같은 변수로 int, double 타입 모두 같은 변수로 관리enum 으로 연산 관리//제네릭 클래스 생성(Getter, Setter)
public class ArithmeticCalculatorData<T extends Number> {
private T firstNum;
private T secondNum;
private char operator;
private T resultNum;
Number 클래스 상속 → 숫자 타입 (Integer, Double, Float, Long, Short, Byte) 만 가능//숫자 입력 부분
ArithmeticCalculatorData calData = new ArithmeticCalculatorData<>();
double tempNum;
while (true) {
System.out.println("\n첫번째 숫자를 입력하세요");
System.out.print("숫자 입력 : ");
try {
tempNum = sc.nextDouble();
if (isInt(tempNum)) {
calData.setFirstNum((int) tempNum);
} else {
calData.setFirstNum(tempNum);
}
break;
} catch (Exception e) {
System.out.println("숫자를 제대로 입력해 주세요");
sc.nextLine();
}
}
// int,double 판독 메서드
public static boolean isInt(double num) {
// int 값의 범위를 벗어나거나
if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE) {
return false;
} else return num % 1 == 0.0; // 정수인지 판독 (실수일경우 소수점이 남음)
}
int, double 모두 받을 수 있음nextInt → nextDouble 로 수정double 값이 int 로 변환 가능한지 확인하는 메서드 추가int 의 범위를 벗어나면서(조건1), 정수일 경우(조건2) int로 판독{[연산 결과{ 5.0 + 6.0 = 11.0 }]} 이런식으로 불필요한 소수점 나오는 것 방지// enum 으로 연산 관리
public enum OperatorType {
PLUS('+', (x, y) -> x + y),
MINUS('-', (x, y) -> x - y),
MULTIPLY('*', (x, y) -> x * y),
DIVIDE('/', (x, y)-> x / y);
// 필드
private final char symbol; // +,-,*,/
private final BiFunction<Double, Double, Double> operate;
// 생성자
OperatorType(char symbol, BiFunction<Double, Double, Double> operate) {
this.symbol = symbol;
this.operate = operate;
}
// 연산 값 리턴
public double operate(double x, double y) {
return operate.apply(x, y);
}
// Symbol 값 리턴 (+,-,*,/)
public char getSymbol() {
return symbol;
}
}
enum 으로 연산을 모두 관리BiFunction 필드에 정의 //파라미터가 2개일 경우
BiFunction<파라미터 1, 파라미터 2, 리턴 값>
//파라미터가 1개일 경우
Function<파라미터 1, 리턴 값>BiFunction 타입의 operate 호출 시 apply() 함수로 미리 정의해둔 람다식 함수 실행public ArithmeticCalculatorData calculate(ArithmeticCalculatorData calData) {
//Number 값으로 담겨있는 값들을 double 타입으로 변환
double resultNum = 0.0;
double firstNum = calData.getFirstNum().doubleValue();
double secondNum = calData.getSecondNum().doubleValue();
char operatorSymbol = calData.getOperator();
//enum 으로 정의 된 operate 함수 사용하여 연산
if(operatorSymbol == OperatorType.PLUS.getSymbol()){
resultNum = OperatorType.PLUS.operate(firstNum, secondNum);
}else if(operatorSymbol == OperatorType.MINUS.getSymbol()){
resultNum = OperatorType.MINUS.operate(firstNum, secondNum);
}else if(operatorSymbol == OperatorType.MULTIPLY.getSymbol()){
resultNum = OperatorType.MULTIPLY.operate(firstNum, secondNum);
}else if(operatorSymbol == OperatorType.DIVIDE.getSymbol()){
resultNum = OperatorType.DIVIDE.operate(firstNum, secondNum);
}
//결과값은 int,Double 판독하여 객체로 담는다.
if (isInt(resultNum)) calData.setResultNum((int)resultNum);
else calData.setResultNum(resultNum);
return calData;
}
getSymbol() 로 비교 하기 위해서 기존 case 문에서 if-else 문으로 변경 enum에서 수행하고 해당 함수만 호출하는 형식으로 변경Number 타입으로 담겨있기 때문에 doubleValue() 로 double 타입으로 변경 후 연산isInt() 메서드로 double,int 판단 후 해당 값으로 Set첫번째 숫자를 입력하세요
숫자 입력 : 64.565
연산자를 입력하세요
연산자 입력 : -
두번째 숫자를 입력하세요
숫자 입력 : 44
연산 결과 : 20.565
전체 결과{[연산 결과{ 64.565 - 44 = 20.565 }]}
int 타입은 정수로 double 타입은 소수점 추가하여 출력//Scanner 입력 값 보다 결과 값이 높은 결과만 조회하는 메서드
public void checkUpperResult(ArithmeticCalculator cal, Scanner sc){
if (cal.getResultList().isEmpty()) {
System.out.println("연산 데이터가 존재하지 않습니다.");
return;
}
while(true){
try {
System.out.println("숫자를 입력해주세요. 입력값보다 높은 결과값이 조회됩니다.");
double inputNum = sc.nextDouble();
sc.nextLine();
//필터활용하여 새로운 데이터 조회
List<ArithmeticCalculatorData> list = cal.getResultList().stream()
.filter(result -> result.getResultNum().doubleValue() > inputNum)
.collect(Collectors.toList());
//list 출력
System.out.println("\n"+inputNum+"보다 높은 결과 : "+list);
return;
} catch (Exception e) {
System.out.println("똑바로 입력해 주세요.");
sc.nextLine();
}
}
}
nextDouble() 로 입력 값 생성 (문자, 기호 입력 시 에러)Stream 기능 사용하여 조회 할 리스트 생성 후 결과 값 출력filter() 부분의 inputNum 의 비교 연산자 변경으로 결과 값 조절 가능문제점
Number 타입의 변수로 직접적인 연산 시도했으나 오류 발생Number num1 = 2;
Number num2 = 3;
Number result = num1 + num2 // 오류 발생원인
int, double 같은 기본형은 연산자로 연산이 가능하다Number 객체에는 적용이 불가능해결
Number num1 = 5;
Number num2 = 3;
//int 타입
int resultInt = num1.intValue() + num2.intValue();
//double 타입
double resultDouble = num1.doubleValue() + num2.doubleValue();Integer, Double 같은 래퍼클래스도 연산은 가능하다. 하지만 기본형처럼 직접적인 연산이 아니 자바의 오토언박싱 기능으로 자동 박싱/언박싱 해주는 것이다.문제점
double 타입끼리 연산 시 소수점 자리가 비정상 출력되어 나오는 현상**연산 결과{ 54.55 + 22.4 = 76.94999999999999 }**원인
double 타입은 2진수 기반 부동소수점 방식으로 값을 저장하는데, 10진수 소수를 2진수로 완벽하게 표현할 수 없는 경우가 많다.double 값 그대로 저장되어 있는 것이다.해결
DecimalFormat() 메서드 사용System.out.println(
new DecimalFormat("#.############").
format(calData.getResultNum()));
//출력 결과 : 54.55 + 22.4 = 76.95 double 값은 바꾸지 않고 출력문 형식만 변경해서 보여줄 수 있다.Math.round 로 특정 위치까지 반올림하여 처리 할 수도 있다.