TIL

[250310 TIL] 스트림으로 리스트 중복 개수 세기

도원좀비 2025. 3. 10. 20:07

오늘 가장 어려웠던 코드

// 중복 메뉴 합산 처리
cartItems.stream()// 스트림으로 변환
        .collect(Collectors.groupingBy(item -> item, Collectors.counting())) // 개수 미리 계산
        .entrySet().stream()
        .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);
        });

 

코드 분해해서 이해하기

코드 설명
cartItems.stream() 장바구니 목록을 스트림으로변환
.collect(Collectors.groupingBy(
item -> item, Collectors.counting()))
cartItems에 있는 동일한 MenuItem을 그룹화하고 개수를 계산해서 Map에 저장
groupingBy(item -> item) : 동일한 MenuItem을 그룹화
Collectors.counting() : 그룹별 개수를 세서 Long값으로 저장
.entrySet().stream() Map을 스트림으로 변환
.sorted(Map.Entry.comparingByKey
(Comparator.comparing
(MenuItem::getName)))
메뉴 이름 기준으로 정렬
MenuItem객체의 getName()값을 기준으로 오름차순 정렬
Map.Entry.comparingByKey() : 키(MenuItem)를 기준으로 정렬
Comparator.comparing(MenuItem::getName) : 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); });
최종 출력
entry.getKey() : MenuItem 객체 가져오기
entry.getValue() : 해당 MenuItem이 몇 개 있는지 가져오기
totalItemPrice = item.getPrice() * count; : 개수에 맞춰 총 가격 계산
index.getAndIncrement : 출력할 때 번호 자동 증가

이거 한다고 머리 빠지는 줄 알았다....

 

코드의 흐름

1. cartItems.stream()
→ 장바구니 목록을 스트림으로 변환
2.. collect(Collectors.groupingBy(item -> item, Collectors.counting()))
→ 같은 메뉴를 그룹화하고 개수를 센다 (Map<MenuItem, Long>)
3.. entrySet(). stream()
→ Map을 스트림으로 변환하여 다룰 수 있게 한다
4.. sorted(Map.Entry.comparingByKey(Comparator.comparing(MenuItem::getName)))
→ 메뉴 이름을 기준으로 정렬한다
5.. forEach(entry -> {... })
→ 출력 형식대로 한 줄씩 출력한다

 

오늘 처음 써본 자바 기능

AtomicInteger : int , Integer는 멀티스레드 환경에서 동기화 없이 값을 변경하면 예상치 못한 오류가 발생할 수 있지만 Atomic Integer는 내부적으로 CAS(Compare-And-Swap) 알고리즘을 사용하여 동기화 없이 안전하게 값을 변경

 

사용이유 : forEach문에서 

int index = 1;

cartItems.stream()
    .forEach(item -> {
        System.out.printf("%d. %s%n", index++, item.getName()); 
    });

 이런 식으로 사용하려고 하니 오류가 발생해서

AtomicInteger index = new AtomicInteger(1);

cartItems.stream()
    .forEach(item -> {
        System.out.printf("%d. %s%n", index.getAndIncrement(), item.getName());
    });

AtomicInteger를 사용해서 값을 안전하게 증가시키면서 출력 가능

 

AtomicInteger 주요 메서드

메서드 설명
get() 현재 값을 가져온다.
set(int newValue) 값을 새로운 값으로 설정한다.
incrementAndGet() 현재 값을 1 증가시키고, 증가된 값을 반환한다.
getAndIncrement() 현재 값을 더한 후 새로운 값을 반환한다.
addAndGet(int a) 주어진값을 더한 후 새로운 값을 반환한다.
getAndAdd(int a) 현재 값을 반환하고, 이후 주어진 값을 더한다.
compareAndSet(int expect,int update) 현재 값이 기대값(expect)과 같다면 업데이트(update)한다.

 

키오스크 LV.6 코드

https://github.com/sukh115/Kiosk/tree/main/src/kioskLv6

 

Kiosk/src/kioskLv6 at main · sukh115/Kiosk

Contribute to sukh115/Kiosk development by creating an account on GitHub.

github.com