Java 스트림

랏 뜨·2024년 11월 29일

🔎 Overview

 자바를 공부하다보면, 스트림을 활용하는 코드들이 눈에 들어온다.

 처음에는 무식하게 반복문을 돌리면서 하나하나씩 코딩하다가도, 스트림을 사용할 수 있게 되어 적용해보면 굉장히 깔끔하고 가독성 있는 코드를 작성할 수 있게 된다.

 그렇다면 스트림이란 무엇이고, 언제 사용해야 하는 것일까?


스트림이란?

  • 데이터의 흐름(데이터 스트림)을 추상화하여 함수형 프로그래밍 방식으로 데이터를 처리하게 도와주는 API
  • 컬렉션, 배열 등의 데이터를 함수형 프로그래밍 방식으로 처리하기 위해 사용
  • 스트림이라는 긴 파이프를 생성하고, 그 안에 있는 데이터를 하나씩 다룬다고 생각하면 편함
  • for, while 등 반복문 대신 사용하며, 보다 깔끔하고 가독성 있는 코드를 작성할 수 있음

스트림의 구성

1. 스트림 생성

  • 컬렉션, 배열 등에서 스트림을 생성

2. 중간 연산

  • 값을 처리하기 위한 중간 연산을 수행
  • 최종 연산이 없으면 실행되지 않으며, 값 또한 얻을 수 없음
    • 이는 스트림이 일회성이기 때문
    • 한 번 파이프에서 나오면, 다시 파이프로 들어가지 않는 한 파이프 안의 요소들을 다룰 수 없음
    • 그러므로 이후 사용할 데이터라면, 파이프 내의 요소들을 잘 살펴본 뒤 값을 꼭 저장해주어야 함

📚 중간 연산의 종류

  1. filter(Predicate<? super T> predicate)
  • predicate -> T와 상위 타입들을의 값을 인자로 받고, Boolean을 리턴
  • 조건식을 통해 참인 것만 솎아냄
  1. map(Function<? super T, ? extends R> mapper)
  • mapper -> T와 상위 타입들을 인자로 받고, R과 하위 타입으로 반환
  • stream 내의 요소들을 각각 변환
  1. faltMap(Function<? super T,? extends Stream<? extends R>> mapper)
  • T와 상위 타입들을 인자로 받고, R과 하위 타입들로 구성된 스트림으로 반환
  • 입력된 요소에 대해 스트림을 생성하고, 이 스트림들을 하나의 스트림으로 결합
  • 이차원 배열, 컬렉션 내 컬렉션 등, 하나의 스트림으로 연결하기 어려울 때 사용
  1. sorted() / sorted(Comparator<? super T> comparator)
  • 정렬
  • 기본적으로 오름차순
  • comparator를 통해 정렬 방법 변경 가능
  1. distinct()
  • 중복 제거
  1. limit(long n)
  • n개 만큼만 뽑음
  1. skip(long n)
  • n개 만큼 건너뜀


3. 최종 연산

  • 스트림 결과를 반환하며, 스트림은 소모되어 사라짐
  • 중간 연산 없이도 사용할 수 있으며, 중간 연산이 있을 시 중간 연산으로 나온 결과를 연산

🚩 최종 연산의 종류

  1. collect(Collector<? super T, A, R> collector)
  • A는 중간 결과를 누적하는 객체의 타입
  • 스트림 요소 처리 결과를 누적하여 저장
  • T와 상위 타입들을 요소로 받고, 요소를 처리하고 누적하여 저장 후, R로 변환해서 반환
  • 일반적으로 Collectors 클래스의 메서드로 생성
  • ex) toList(), toSet(), groupingBy()...
  1. forEach()
  • 스트림을 돌며 하나씩 소비
  • 흔히 사용하는 반복문 개념
  1. reduce(BinaryOperator accumlator) ...
  • 스트림의 각 요소를 누적하여 축소
  • 두 T 값을 받아서 하나의 T값을 리턴하고, 이러한 연산을 반복 수행하여 그 값을 차례대로 누적
  1. count()
  • 연산 결과로 나온 요소의 총 개수를 반환
  1. allMatch()
  • 모든 요소가 조건을 만족하는지 확인
  1. anyMatch()
  • 조건을 만족하는 요소가 하나라도 있는지 확인
  1. noneMatch()
  • 조건을 만족하는 요소가 하나도 없는지 확인
  1. findFirst()
  • 연산의 결과로 나온 첫번째 요소를 반환
  • limit(1)과 동일


// 그 외에도 다양한 중간 및 최종 연산이 존재하며, 매개변수도 다양하게 올 수 있다.


🤔 그렇다면 언제 스트림을 사용하면 좋을까

1. 보다 가독성 있고 깔끔한 코드를 작성하고 싶을 때

  • 반복문을 사용하면 대부분 코드가 길고 지저분해질 수 밖에 없는데, 스트림을 활용하면 몇 줄 이내에 깔끔하게 구현이 가능함
  • 함수형 인터페이스를 통해 작성하기 때문에 가독성을 높여주고 유지보수 또한 쉽게 할 수 있음

2. 대량 데이터를 병렬 처리로 처리할 때

  • 대량 데이터를 다룰 때 병렬 스트림을 활용하면, 멀티코어 CPU의 성능을 최대한 이용할 수 있음

3. 데이터를 한 번 쓰고 버릴 때

  • 스트림은 재사용이 불가한 일회용
  • 한 번 쓰고 버릴 데이터를 작업하기에 적합

참고) OpenAI. (2024).ChatGPT(4o)[Large language model].https://chatgpt.com/

profile
기록

0개의 댓글