stream 만들어낸 이유가 있지 않을까?

2024. 12. 4. 23:03·Dev

글을 작성하는 이유

Java로 개발을 하다 보면 컬렉션이나 배열의 요소를 처리할 때 for문 대신 Stream을 사용하는 코드를 자주 마주하게 됩니다. 더 빠르다는 말에 이끌려 저 또한 Stream을 사용했습니다. 하지만 최근 들어 단순히 빠르다는 이유만으로 기술을 선택하는 것은 안일하다는 생각이 들었습니다. '왜 Stream을 사용해야 할까?'라는 근본적인 질문에 대한 답을 찾고 싶어졌습니다. 그리고 좋은건 더 공부해서 적극적으로 사용해야 한다고 생각했습니다.

for문과 Stream, 어떤 차이가 있을까?

특징 for문 Stream
개념 명시적인 반복 함수형 스타일의 데이터 처리
구조 순차적인 실행 파이프라인 구성
장점 직관적, 간단한 로직 가독성, 유지보수성, 병렬 처리 가능
단점 복잡한 로직에서 가독성 저하, 병렬 처리 어려움 학습 곡선, 성능 오버헤드 (일부 경우)

Stream 쓰는 이유

1. 필요한 요소만 처리

  • 지연 처리는 중간 연산을 누적하지 않고 최종 연산이 필요로 하는 만큼만 수행합니다.
  • 지연 처리는 최종 연산에서 필요하지 않은 중간 연산이 있다면 이를 수행하지 않습니다.

2. 연산 합성

  • 지연 처리를 통해 중간 연산들이 합쳐져서 한 번에 처리됩니다.
  • 예를 들어, filter와 map이 연속으로 적용될 때, 각 요소에 대해 한 번의 순회로 filter와 map을 동시에 수행합니다.

여러 번 순회할 필요가 없어집니다!

stream의 프로세스

1. 생성

  • Stream은 컬렉션(List, Set 등), 배열, 또는 I/O 채널 등에서 데이터를 가져와 생성할 수 있습니다.
    예를 들어, 
    List<String> list = Arrays.asList("a", "b", "c");
    에서 list.stream()을 호출하면 Stream<String>이 생성됩니다.

2. 중간 연산

  • 중간 연산은 스트림의 데이터를 가공하는 과정입니다. filter(), map(), sorted() 등이 있습니다. 각 연산은 스트림의 요소를 처리하지만 즉시 실행하지는 않습니다.
  • 중간 연산은 지연 처리 방식으로 동작하므로 최종 연산이 호출될 때까지 수행되지 않습니다.
  • 3. 최종 연산
  • 최종 연산은 스트림을 닫고 결과를 생성합니다. forEach(), collect(), reduce() 등이 있습니다.
  • 최종 연산이 호출되면 중간 연산들이 실제로 실행됩니다.

메서드 정리

filter

filter는 스트림의 각 요소에 대해 주어진 조건을 검사하여 조건을 만족하는 요소만으로 구성된 새로운 스트림을 생성합니다.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0) // 짝수만 필터링
                                   .collect(Collectors.toList());
System.out.println(evenNumbers); // [2, 4]

map

map은 스트림의 각 요소를 주어진 함수를 사용하여 변환하여, 변환된 요소들로 구성된 새로운 스트림을 생성합니다.

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> nameLengths = names.stream()
                                 .map(String::length) // 각 이름의 길이로 변환
                                 .collect(Collectors.toList());
System.out.println(nameLengths); // [5, 3, 7]

forEach

forEach는 스트림의 각 요소에 대해 주어진 동작을 수행합니다. 최종 연산으로 스트림의 각 요소를 처리하고 결과를 출력하거나 저장할 때 사용됩니다.

List<String> items = Arrays.asList("apple", "banana", "cherry");
items.stream()
   .forEach(System.out::println); // 각 요소 출력

collect

collect는 스트림의 요소들을 수집하여 특정 결과를 생성하는 최종 연산입니다. 주로 Collectors를 사용하여 리스트, 집합, 맵 등으로 결과를 수집할 수 있습니다.

List<String> fruits = Arrays.asList("apple", "banana", "cherry");
List<String> upperFruits = fruits.stream()
                               .map(String::toUpperCase)
                               .collect(Collectors.toList()); // 대문자로 변환하여 리스트로 수집
System.out.println(upperFruits); // [APPLE, BANANA, CHERRY]

참고: https://futurecreator.github.io/2018/08/26/java-8-streams-advanced/

'Dev' 카테고리의 다른 글

Index를 생성해서 약 10배 성능 개선  (0) 2024.12.04
N+1 문제 해결해서 성능 개선하기  (0) 2024.12.04
일단 단위 테스트부터 테스트 코드 작성해보기  (0) 2024.12.04
상품 주문하기 동시성 문제 해결하기  (0) 2024.12.04
과도한 트래픽에 대한 방어하기  (1) 2024.12.04
'Dev' 카테고리의 다른 글
  • Index를 생성해서 약 10배 성능 개선
  • N+1 문제 해결해서 성능 개선하기
  • 일단 단위 테스트부터 테스트 코드 작성해보기
  • 상품 주문하기 동시성 문제 해결하기
khjoon
khjoon
  • khjoon
    기록기록
    khjoon
  • 전체
    오늘
    어제
    • 분류 전체보기 (37)
      • Security (2)
      • Dev (14)
      • Infra (12)
      • Ops (9)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
khjoon
stream 만들어낸 이유가 있지 않을까?
상단으로

티스토리툴바