TIL

[250312 TIL] JAVA 키오스크 프로젝트 개선

도원좀비 2025. 3. 12. 19:37
 

📌 TIL (Today I Learned) - Java 키오스크 프로젝트 개선 🛠️


🍔 1. double 대신 Integer로 가격 타입 변경 (가격 단위 정리)

🔹 이전 코드 (double 사용)

private final Double price; // 가격을 double로 설정

문제점

  • 부동소수점 연산 오차 발생 가능
  • 가격에 소수점이 필요 없음에도 double을 사용하여 불필요한 메모리 사용

개선 코드 (Integer로 변경)

private final Integer price; // 가격을 Integer로 변경

💡 개선 효과

  • 정확한 가격 계산 가능 (소수점 연산 문제 해결)
  • 메모리 절약 (4바이트 vs 8바이트)
  • 가독성 및 유지보수 용이

📂 관련 파일: MenuItem


🏷️ 2. Discount 클래스를 List 기반으로 변경 (할인 데이터 구조 개선)

🔹 이전 코드 (Discount[] 사용)

public static void printDiscountList(Discount[] discounts) {
    IntStream.range(0, discounts.length)
            .forEach(i -> System.out.println(
                    String.format("%d. %s || %.0f%%",
                            i + 1,
                            discounts[i].getDiscountCategory(),
                            discounts[i].getDiscountRate() * 100)
            ));
}

문제점

  • Discount[] 배열은 가변성이 부족하고, 크기 변경이 어렵다.
  • List<Discount>를 활용하면 더 유연하게 활용 가능.

개선 코드 (List<Discount> 사용)

public static void printDiscountList(List<Discount> discounts) {
    IntStream.range(0, discounts.size())
            .forEach(i -> System.out.println(
                    String.format("%d. %s || %.0f%%",
                            i + 1,
                            discounts.get(i).getDiscountCategory(),
                            discounts.get(i).getDiscountRate() * 100)
            ));
}
 

📌 개선 효과

  • 가변성이 뛰어난 List 활용
  • 배열보다 유지보수 편리
  • 컬렉션 프레임워크 사용으로 일관성 유지

📂 관련 파일: Discount


🔄 3. Map 대신 List 기반의 장바구니 구현

🔹 이전 코드 (Map을 활용한 메뉴 장바구니 메뉴)

 private final List<MenuItem> cartItems = new ArrayList<>();
 
 // 장바구니에 메뉴 추가
    public void addItem(MenuItem item) {
        cartItems.add(item);
        System.out.println(item.getName() + "이(가) 장바구니에 추가되었습니다.");
    }

    // 장바구니에서 특정 메뉴 제거
    public void removeItem(int index) {
        if (index >= 0 && index < cartItems.size()) {
            MenuItem removedItem = cartItems.get(index);
            cartItems.remove(index); // 삭제 메서드호출
            System.out.println(removedItem.getName() + "이(가) 장바구니에서 삭제되었습니다.");
        } else {
            System.out.println("잘못된 선택입니다. 다시 입력하세요.");
        }
    }

    // 장바구니 목록 출력
    public void displayCart() {
        if (cartItems.isEmpty()) {
            System.out.println("장바구니가 비어 있습니다.");
            return;
        }

        System.out.println("=== 장바구니 목록 ===");

        AtomicInteger index = new AtomicInteger(1); //AtomicInteger로 forEach문 index 변경가능

        // 중복된 메뉴 개수를 계산하고 정렬하여 출력
        cartItems.stream()// 스트림으로 변환
                .collect(Collectors.groupingBy(item -> item, Collectors.counting())) // 개수 미리 계산
                .entrySet().stream() // Map을 스트림으로 변환
                .sorted(Map.Entry.comparingByKey(Comparator.comparing(MenuItem::getName))) // 정렬 추가
                .forEach(entry -> { // 최종 출력
                    MenuItem item = entry.getKey();
                    long count = entry.getValue();
                    double totalItemPrice = item.getPrice() * count;
                    System.out.printf("%d. %s | %d개 | W %.2f%n", index.getAndIncrement(), item.getName(), count, totalItemPrice);
                });


        System.out.println("총 금액: W " + calculateTotal());
    }

문제점

  • 같은 메뉴가 여러 번 추가되면 중복 항목을 직접 찾아서 개수를 세어야 함
  • 특정 메뉴 삭제 시 모든 항목을 탐색해야 하는 비효율성
  • 개수를 출력하려면 groupingBy()를 사용하여 추가적인 연산 필요

개선 코드 (가독성 향상 및 성능 개선)

    public void removeItemByName(String itemName) {
        Optional<MenuItem> removeTOItem = cartItems.keySet().stream()
                .filter(item -> item.getName().equalsIgnoreCase(itemName))
                .findFirst();

        if(removeTOItem.isPresent()) {
            removeItem(removeTOItem.get());
        }else {
            System.out.println("해당 메뉴가 장바구니에 없습니다.");
        }
    }

📌 개선 효과

  • 같은 메뉴를 여러 번 추가해도 자동으로 개수 증가
  • 삭제 시 특정 키(MenuItem)를 바로 찾아서 개수만 감소
  • 총 금액 계산 및 출력이 더 직관적으로 가능

📂 관련 파일: Cart


📋 4. viewCart()의 입력 처리 개선 (메뉴 삭제 시 입력 오류 방지)

🔹 이전 코드 (숫자 입력만 받음)

int option = getValidIntInput(); // ❌ 문자열 입력 시 오류 발생
if (option == 1) {
    System.out.print("삭제할 메뉴 이름을 입력하세요 ");
    String itemName = scanner.nextLine().trim();
    cart.removeItemByName(itemName);
}

문제점

  • 사용자가 "감자 튀김" 같은 메뉴 이름을 입력하면 입력 오류 발생
  • getValidIntInput()이 숫자만 받도록 구현되어 있어 문자열 입력 불가

개선 코드 (숫자 입력과 문자열 입력을 분리)

int option = getValidIntInput();  // ✅ 숫자 입력만 받음
if (returnHome(option)) return;

if (option == 1) {
    System.out.print("삭제할 메뉴 이름을 입력하세요: ");
    String itemName = scanner.nextLine().trim();  // ✅ 문자 입력 허용
    cart.removeItemByName(itemName);
} else {
    System.out.println("⚠️ 잘못된 입력입니다. 다시 선택해주세요.");
}

📌 개선 효과

  • 숫자 입력 (1, 0, -1)과 메뉴 삭제 문자열 입력을 분리
  • 입력 오류 방지 및 사용자 경험 향상

📂 관련 파일: Kiosk


🎯 5. getValidIntInput()에서 입력 예외 처리 강화 (잘못된 숫자 입력 처리)

🔹 이전 코드 (예외 처리 부족)

private int getValidIntInput() {
    try {
        int input = scanner.nextInt();
        scanner.nextLine();  // 개행 문자 제거
        return input;
    } catch (InputMismatchException e) {
        scanner.nextLine();  // 버퍼 비우기
        System.out.println("유효하지 않은 입력입니다. 숫자를 입력하세요.");
        return -1;  // 잘못된 입력 시 기본값 반환
    }
}

문제점

  • scanner.nextInt()는 숫자 입력 후 개행 문자(\n)를 남겨서 다음 입력 시 문제 발생 가능
  • 예외 발생 시 버퍼를 비우는 추가 코드(scanner.nextLine())가 필요
  • 문자 입력 시 InputMismatchException 발생

개선 코드 (입력 흐름 유지 및 명확한 메시지 추가)

    private int getValidIntInput() {
        while (true) {
            try {
                int input = Integer.parseInt(scanner.nextLine().trim());
                return input;
            } catch (NumberFormatException e) {
                System.out.println("유효하지 않은 입력입니다. 숫자를 입력하세요.");
            }
        }
    }

📌 개선 효과

  • scanner.nextInt() 대신 scanner.nextLine()을 사용하여 버퍼 문제 해결
  • 예외 발생 시 루프를 돌면서 사용자가 숫자를 입력할 때까지 반복 요청
  •  숫자가 아닌 입력을 받을 경우 NumberFormatException을 처리하여 프로그램이 중단되지 않도록 개선
  •  trim()을 사용하여 공백을 포함한 잘못된 입력 방지

📂 관련 파일: Kiosk


🛠️ 오늘의 개선 요약

✅ double price → Integer price로 변경하여 연산 오류 방지
✅ Discount[] → List<Discount>로 변경하여 더 유연한 데이터 구조 사용
✅ removeItemByName() 가독성 및 성능 개선
✅ viewCart()에서 숫자/문자 입력 오류 방지
✅ getValidIntInput()에서 예외 처리 강화