[Java] Stream 함수에서 인덱스 사용하기 (키오스크 과제)

2025. 1. 16. 21:16·공부하기/Java

💥 Stream 함수에서 인덱스 사용

발단 : forEach() 에서 인덱스 정보가 필요해!

`기존에 생성한 Menu의 MenuItem을 조회 할 때 스트림을 사용하여 출력하도록 수정`하라는 요구사항에 맞게,

`Menu` class의 `printMenuItems()` 메서드를 변경하고자 하였다.

기존 코드

    // List에 들어있는 MenuItem을 순차적으로 보여주는 함수
    public void printMenuItems() {
        for(int i=0; i<menuItems.size(); i++) {
            System.out.print(i+1 + ". ");
            System.out.println(menuItems.get(i));
        }
    }

위 함수를 실행하면 다음과 같이 인덱스와 함께 메뉴 아이템의 정보가 출력된다.

1. ShackBurger        | W 6.9 | 토마토, 양상추, 쉑소스가 토핑된 치즈버거
2. SmokeShack         | W 8.9 | 베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거
3. Cheeseburger       | W 6.9 | 포테이토 번과 비프패티, 치즈가 토핑된 치즈버거
4. Hamburger          | W 5.4 | 비프패티를 기반으로 야채가 들어간 기본버거

 

`Menu` class는 필드로 `private final List<MenuItem> menuItems`를 가지고 있다.

menuItems에 대해서 stream을 생성하고 `forEach` 중간 함수를 통해서 `MenuItem 요소`와 요소의 순서를 가져오는 `index 데이터`를 가져와서 출력을 하면 되겠다고 생각했다.

그런데 ... 문제가 발생했다.

wrong number of parameters: expected 1 but found 2

내가 JS의 forEach 함수와 혼동했던 것 ..

Java stream의 forEach 함수의 콜백함수에 들어갈 수 있는 매개변수는 오직 1개, 스트림 요소를 담을 변수뿐이다.

 

근데 인덱스를 사용 못 하는게 말이 돼??? 일단 방법을 생각해봤다.

전개 : index 변수를 선언해서 쓰자

변수 `idx`를 선언하고, forEach 함수 내에서 사용해보려고 했다.

코드는 다음과 같다.

    public void printMenuItemsWrongVer() {
        int idx = 1;
        menuItems.stream().forEach((item)-> {
            System.out.printf("%d. %s\n",idx++,item);
        });
    }

이번엔 다음과 같은 에러가 다시 발생했다.

Variable used in lambda expression should be final or effectively final

람다 표현식 안에서 사용되는 변수는 final이거나 final처럼 동작해야 한다는 것이다.

그래서 함수가 종료됨과 동시에 사라지는 `idx`변수는 람다 표현식 내에서 사용하려고 하면 에러가 발생한다.

 

해결 방법을 찾아보자!

 


해결 ✅ IntStream 사용

스트림을 이용해서 for문처럼 특정 범위동안 반복적인 작업을 하고 싶을 때 IntStream을 주로 사용하는 것 같다.

`IntStream` - 정수 데이터에 대한 stream을 구성할 수 있다.
- `range(start,end)` : start ~ end-1 까지의 정수 데이터로 스트림을 구성한다.
- `rangeClosed(start,end)` : start ~ end 까지의 정수 데이터로 스트림을 구성한다.
- `of(num1, num2, …)` : 지정된 값을 포함하는 정수 스트림을 구성한다.

인덱스로의 활용 방법

IntStream을 구성한 뒤, IntStream의 중간함수 forEach에서 작업을 수행한다.

public void printMenuItems() {
    IntStream.range(0,menuItems.size())
            .forEach(idx -> System.out.printf("%d. %s\n",idx+1,menuItems.get(idx)));
}

이해하기가 쉽고 직관적이라 이 방법을 채택했다!

해결 ✅ AtomicInteger 사용

아까 마주한 에러 문구를 다시 보면, 인텔리제이가 'Convert to atomic'을 하라고 권유하는 것을 볼 수 있다.

눌러보면 코드가 다음과 같이 바뀐다.

    public void printMenuItems() {
        AtomicInteger idx = new AtomicInteger(1);
        menuItems.stream().forEach((item)-> {
            System.out.printf("%d. %s\n", idx.getAndIncrement(),item);
        });
    }

`AtomicInteger` 라는 객체는 람다표현식 내에서 인덱스처럼 사용할 수 있다.

개인적으로 이번에 처음 본 클래스라 조금 더 찾아봤다.

Atomic 클래스

`Atomic클래스` : 멀티쓰레드 환경에서 동시성을 보장해주는 클래스
- CAS(Compare And Swap)방식에 기반하여 동기화 문제 해결
- 변수의 값을 변경하기 전에 확인한 값이 내가 예상하던 값과 같을 경우에만 새로운 값으로 변경해준다.

이렇게 알아서 동시성을 보장해주는 Atomic 클래스의 종류는 다음과 같다.

많구나??

`AtomicInteger` : 멀티쓰레드 환경에서 동시성을 보장해주는 Integer 변수
- `get()` : 메모리에서 값을 가져온다.
- `set()` : 메모리에 값을 저장한다.
- `compareAndSet()` : 메모리에 값을 바꾸는데(저장) 성공하면 true, 실패하면 false를 리턴한다.
- `getAndIncrement()` : 값을 가져온 후 1 증가시킨다.

 

AtomicInteger, AtomicBoolean과 같은 객체 변수는 람다 표현식에서 사용 가능하다.

람다 표현식에서 사용하는 변수는 `final` 혹은 `사실상 final`이어야 하는데, Atomic 클래스 객체는 사실상 final에 속하는 것이다.

 

기존에 사용하던 idx 사용과 가장 유사하게 구현할 수 있지만, 현재 구현에서 동시성 보장 로직을 구태여 실행하게 할 필요는 없는 것 같아 사용하진 않았다.


저작자표시 비영리 변경금지 (새창열림)

'공부하기 > Java' 카테고리의 다른 글

[Java] HashMap 파헤쳐보기 (키오스크 과제 : 장바구니 구현기)  (0) 2025.01.20
🧐 계산기 과제를 마무리하는데 생겨난 궁금증 : Generics 사용  (0) 2025.01.09
계산기 과제 : 계산 결과 Lambda&Stream 필터링 조회 구현하기  (2) 2025.01.07
[Java] 추상클래스 vs 인터페이스, 언제 어떤 것을 사용할까?  (1) 2025.01.07
계산기 과제 : Java Generics, Enum 활용기  (0) 2025.01.06
'공부하기/Java' 카테고리의 다른 글
  • [Java] HashMap 파헤쳐보기 (키오스크 과제 : 장바구니 구현기)
  • 🧐 계산기 과제를 마무리하는데 생겨난 궁금증 : Generics 사용
  • 계산기 과제 : 계산 결과 Lambda&Stream 필터링 조회 구현하기
  • [Java] 추상클래스 vs 인터페이스, 언제 어떤 것을 사용할까?
다섯자두
다섯자두
All I need is 💻 , ☕️ and a dash of luck
  • 다섯자두
    subbni
    다섯자두
  • 전체
    오늘
    어제
    • 전체 글 (89)
      • 개발 이야기 (0)
      • 만들어보기 (17)
        • FromBookToBook (5)
        • Spring (5)
        • Node.js & React (3)
        • TroubleShooting (4)
      • 공부하기 (72)
        • Network (3)
        • Cloud (1)
        • Database (5)
        • Java (13)
        • Javascript (0)
        • Spring (9)
        • React (18)
        • Algorithm (8)
        • 자료구조 (7)
        • ETC (8)
      • 회고 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • velog
  • 공지사항

  • 인기 글

  • 태그

    pdf 프리뷰 실패
    로그인
    JPA
    Express
    프로젝트
    실시간 데이터 전송 기술
    알림 기능
    서명알고리즘
    Database
    network
    Spring
    재시도 로직
    HTTP
    pdf 자동 다운로드
    SSE
    Til
    자료구조
    outbox 패턴
    aws
    java
    오블완
    티스토리챌린지
    springboot
    outbox
    mysql
    redis
    알고리즘
    최단거리
    SQS
    SQL
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
다섯자두
[Java] Stream 함수에서 인덱스 사용하기 (키오스크 과제)
상단으로

티스토리툴바