Notice
Recent Posts
Recent Comments
Link
«   2026/10   »
일 월 화 수 목 금 토
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

seaking110 님의 블로그

계산기 만들기 본문

Today I Learned

계산기 만들기

seaking110 2025. 1. 10. 09:51

 

요구사항 정의 및 설계

숫자를 2개 입력 문자를 1개 입력 그 후 해당 숫자와 문자들로 사칙연산을 계산한 뒤 결과값 반환하기

  • App 클래스의 main 메서드에서는 입력만을 받아오는 역할
  • calculator 클래스를 활용해서 연산 수행 담당
  • 연산 결과를 컬렉션으로 저장 또한 Calculator 클래스가 컬렉션 타입 필드를 가지고 있어야함

 

 

고민 사항

Lv 1

  • 계산기에서 + - *까지 리턴 값이 int형인데 /에선 double형으로 리턴해줘야한다. 
    • 일관성을 위해 + - * 모두 실수로 반환하자 

Lv 2

  • switch의 default에 연산기호가 아닌 숫자가 들어왔을 때 오류 처리를 해주고 continue를 해줬엇는데 클래스를 나누고 리턴 값을 줘야할 때는 어찌할지 고민이다.
    • 2단계에선 예외를 신경쓰지 말라는 피드백을 받고 삭제 
    • Lv 3에서는 입력 메서드를 따로 만들고 안에서 무한루프를 돌고 numberFormatException을 이용해서 예외 처리
  • 예외 처리에 대한 부분은 많이 진행하지 않아봤는데 DivideException 이라는 예외 클래스를 만들고 두번째 숫자가 0이면 에러가 발생하게 만들었다. 또한 연산기호가 아닌 다른 것을 입력했을 때 예외 처리를 하려고 예외 클래스를 하나더 만들었더니 Throw로 해당 메소드에 연결이 안된다.  
    • 방법을 찾아보니 하나의 큰 Exception 클래스를 만들고 두개의 별도의 클래스로 상속하여 연결하여 관리하기 vs 다중 예외 클래스를 하나로 통합하여 만들기

Lv 3

  • 입력을 받을때 double이나 int로 받았을때 메서드의 리턴 값이 문제다 T로 리턴을 해야할 텐데 double 값을 다시 T로 변경해서 리턴하는 방법이 있나?
  • 전역 변수로 타입을 지정해서 할 수 있겠지만 해당 계산기가 어떤 타입인지 알 수 있는 방법이 없을까?
  • cal을 와일드 카드로 지정해주고 시작했더니 아래에서 해결이 안된다 어떻게 해결할까?
  • 같은 클래스에서 필드 접근 방식 고민
    • 아래 쪽 코드는 setLageResult 메서드를 만들어서 이용
    • 캡슐화가 되고 재사용성이 높기때문에 아래 코드 채용
    public List<Double> largeResult(double d) {
        largeResult.clear();
        saveResult.stream().filter(f-> f > d).forEach(f -> largeResult.add(f));
        return getLargeResult();
    }

vs 

    public List<Double> largeResult(double d) {
        largeResult.clear();
        saveResult.stream().filter(f-> f > d).forEach(this::setlargeResult);
        return getLargeResult();
    }

 

 

 

튜터님 피드백

  • 쓸모 없는 파일 삭제 및 정리
    • groovy 쪽에 쓸모 없는 파일이 존재 했다.
    • 필요하지 않는 파일을 push 하는 것은 협업할 때를 위해 항상 조심하자
  • 코드를 가독성 높게 쓰고 자바 문법 준수
    • 제어문 사용 시 띄어쓰기를 잘 안하는 버릇이 있다. 띄어쓰기에 신경 쓰자!
    • else를 바로 뒤에 배치하여 논리적인 조건의 처리를 한 흐름으로 보여주기 편하고 가독성과 else가 독립적으로 쓰이지 않도록 하여 오류를 방지해준다!

 

if (num2 == 0) {
	System.out.println("나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.");
} else {
	double result = (double) num1 / num2;
	System.out.println("결과: "+ result);
}

 

 

  • 예외 클래스를 생성할 때 Exception 보단 RuntimeException을 상속!
    • Exception
      • checked Exception으로 반드시 처리해야하는 예외
      • 코드가 복잡, 개발자가 매번 처리 코드 작성 필요
      • 예외가 반드시 처리되어야 하는 상황에 적합 (파일 입출력, 네트워크 통신)
    • RuntimeException
      • Unchecked Exception으로 예외처리 강제 x
      • throws 선언 없이 사용 가능, 코드가 간결
      • 개발자가 예외를 의도적으로 처리하지 않아도 되지만 프로그램이 종료될 가능성 존재
  • 입력 받는 부분을 try catch 문을 사용하여 모두 처리 
    • 가독성이 너무 떨어져서 입력 받는 메소드를 따로 만들어서 3단계에서 구현  
    • 2단계에선 try-catch문 사용을 필수로 하지 않으니 삭제할 것
  • Arraylist 말고 list로 선언
    • 아래 처럼 해도 틀린 것은 아님 하지만 List는 인터페이스이고 ArrayList는 클래스.
    • 보다 큰 범위로 시작해야 코드의 유연성이 높아 유지보수성이 높아짐
    • 다형성을 활용하여 더 범용적으로 동작 가능
    • 구현보다는 인터페이스에 의존하는 자바의 객체 지향 설계 원칙에 부합
    • 코드의 추상화 수준이 높아지고 유연해짐 
// o
private List<Double> saveResult = new ArrayList<>();
// x
private ArrayList<Double> saveResult = new ArrayList<>();

 

 

  • 더욱 가독성 좋은 개선된 case문으로 람다식 사용
    •  java 14 이후부터 사용 가능
    • yield 키워드를 이용해서 블록 내부에서 반환 값을 설정
return switch (op) {
	case '+' -> add(num1, num2);
	case '-' -> subtract(num1, num2);
	case '*' -> multiply(num1, num2);
	case '/'-> {
		if (num2 == 0) {
			throw new DivideException();
		}
		yield divide(num1, num2);
	}
	default -> throw new InvalidInputValueException();
};

 

 

 

enum을 처음 써본다! 쓰기전에 정리해보자

 

ENUM

  • 열거 타입이라고도 하며 한정된 값만을 갖는 데이터 타입을 의미
  • 자바에서 서로 연관 있는 상수를 관리하기 위해 사용
  • 요일, 순위, 성적 등
public enum Week {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
  • 열거 타입도 데이터 타입의 일종으로 변수를 선언 및 대입 가능
Week today = Week.SUNDAY;
System.out.println(today.name); // SUNDAY
  • valutOf
    • 열거 객체의 상수명과 동일한 문자열을 입력받아 일치하는 것을 반환 
Week tommorow = Week.valueOf("MONDAY");
System.out.println(tommorow); // MONDAY
  • 상수와 연관된 추가적인 데이터를 상수 자체에 포함하여 관리할 수 있다.
  • 일반적인 인스턴스 필드를 사용하는 것 처럼 생성자를 정의하면 된다.
  • 또한 getter setter 또한 제공하므로 이를 이용해서 계산기를 만들어보자

 


 

  • enum을 이용해서 계산기를 만들자 
    • 기존에는 if문을 사용해서 +가 들어오면 PLUS를 붙이는 식으로 코딩했다.
    • 하지만 이런 경우 유지 보수성이 심각하게 떨어지고 ENUM을 사용하는 의미가 없었다
    • 그래서 상수에 연산자를 나타내는 속성을 추가했다
public enum OperatorType {
    PLUS('+'),
    MINUS('-'),
    MULTIPLY('*'),
    DIVIDE('/');
}

 

  • 또한 메서드를 하나 만들어서 값을 비교하여 해당 ENUM 인스턴스를 반환하게 코딩했다
    public char getType() {
        return type;
    }
    // 해당 메서드가 특정 인스턴스에 의존하지 않으니 static을 추가했고
    // values를 사용해서 enum 클래스를 순회하여 같은 값이 있으면 해당 데이터를 리턴
    // 만약 없다면 널 값 리턴
    public static OperatorType findOp(char op) {
        for (OperatorType operator : values()) {
            if (operator.getType() == op) {
                return operator;
            }
        }
        return null; // 유효하지 않은 연산자일 경우
    }

 

 

 

  • 제네릭을 이용하자
    • 먼저 기존 계산기 클래스에 제네릭을 넣고 들어오는 모든 부분과 계산 부분의 값을 제네릭화 했다.
public class ArithmeticCalculator <T extends Number>{
	    public double calculate(T num1, T num2, OperatorType op) {
        return switch (op) {
            case PLUS -> add(num1, num2);
            case MINUS -> subtract(num1, num2);
            case MULTIPLY -> multiply(num1, num2);
            case DIVIDE-> {
                if (num2.doubleValue() == 0) {
                    throw new DivideException();
                }
                yield divide(num1, num2);
            }
        };
    }
        //사칙 연산 메서드
    public double add(T num1, T num2) {
        return num1.doubleValue() + num2.doubleValue();
    }

    public double subtract(T num1, T num2) {
        return num1.doubleValue() - num2.doubleValue();
    }

    public double multiply(T num1, T num2) {
        return num1.doubleValue() * num2.doubleValue();
    }

    public double divide(T num1, T num2) {
        return num1.doubleValue() / num2.doubleValue();
    }
}
  • 결과 값을 저장하는 리스트 부분도 바꿨다가 낭패를 봤다 결과 값은 무조건 double이다! 

 

 

'Today I Learned' 카테고리의 다른 글

키오스크 과제 1일차  (0) 2025.01.13
계산기 만들기 트러블 슈팅  (0) 2025.01.10
모던 자바  (0) 2025.01.08
Thead  (1) 2025.01.07
Generic  (0) 2025.01.06