Stream(스트림)

정승현·2024년 12월 4일

STREAM (흐르다.)
프로그래밍에서는 데이터의 흐름을 의미하며, 연속된 데이터 요소들을 처리하는 기능

💡 스트림 사용 이유

  • 표준화된 데이터 처리를 위해
    • List, Set, Map 등 각각의 컬렉션마다 데이터를 다루는 방식이 다름
    • Collection.sort()와 Arrays.sort()처럼 같은 정렬 기능이더라도 컬렉션 종류에 따라 다른 메서드를 사용해야 했음
  • 병렬처리의 지원으로 대량의 데이터를 빠르고 쉽게 처리할 수 있음
  • 코드의 가독성이 증가함

💡 특징

  • 데이터 소스 불변성
    • 원본 데이터를 변경하지 않고 읽기만 수행
    • 필요한 경우 결과를 새로운 컬렉션에 담아 반환 가능
  • 일회성
    • Iterator처럼 한 번 사용하면 재사용 불가
    • 필요시 새로운 스트림을 생성해야 함
  • 내부 반복
    • 반복 처리를 메서드 내부에서 처리
    • forEach() 등을 통해 간결한 코드 작성 가능
  • 지연 연산
    • 최종 연산이 수행되기 전까지 중간 연산이 실행되지 않음
    • 효율적인 연산 처리 가능

💡 스트림의 연산과 메서드

✍️ 중간 연산 (Intermediate Operations)

  • 스트림을 반환하므로 메서드 체이닝 가능
  • 지연 평가 방식으로 동작
  • 최종 연산이 호출되기 전에 실행 X
메서드반환 타입설명사용 예시예시 설명
distinct()Stream<T>중복을 제거Stream.of("A", "A", "B").distinct()[A, B] 반환, 중복된 A가 제거됨
filter()Stream<T>조건에 안 맞는 요소 제외numbers.stream().filter(n -> n % 2 == 0)짝수만 필터링하여 반환
limit()Stream<T>스트림의 일부를 잘라낸다numbers.stream().limit(3)처음 3개 요소만 선택하여 반환
skip()Stream<T>스트림의 일부를 건너뛴다numbers.stream().skip(5)처음 5개 요소를 건너뛰고 나머지 반환
peek()Stream<T>스트림의 요소에 작업수행stream.peek(System.out::println)각 요소를 출력하면서 스트림 처리, 디버깅용으로 주로 사용
sorted()Stream<T>스트림의 요소를 정렬stream.sorted()자연 순서(오름차순)로 요소 정렬
sorted()Stream<T>구분자를 이용하여 정렬stream.sorted((a,b) -> b-a)Comparator를 이용한 내림차순 정렬
map()Stream<R>스트림의 요소를 변환stream.map(String::toUpperCase)모든 문자열을 대문자로 변환
flatMap()Stream<R>중첩 구조를 단일 구조로 변환stream.flatMap(Arrays::stream)중첩된 리스트를 단일 스트림으로 평면화
mapToInt()IntStream정수 스트림으로 변환stream.mapToIn(String::length)문자열 길이를 정수로 변환
mapToDouble()DoubleStream실수 스트림으로 변환stream.mapToDouble(Integer::doubleValue)정수를 실수로 변환
mapToLong()LongStreamLong 스트림으로 변환stream.mapToLong(Integer::longValue)정수를 long으로 변환

✍️ 최종 연산 (Terminal Operations)

  • 스트림을 소비하여 최종 결과를 생성
  • 한 번만 수행 가능
  • 최종 연산 후 스트림이 닫힘
메서드반환 타입설명예시예시 설명
forEach()void각 요소에 지정된 작업 수행intList.stream().forEach(System.out::println)리스트의 각 요소를 출력
forEachOrdered()void병렬 처리 시에도 순서를 보장하며 작업 수행list1.stream().parallel().forEachOrdered(System.out::println)병렬 처리 시에도 순서대로 출력
count()long스트림의 요소 개수 반환Stream.of(1, -4, 5, -3, 6).filter(x -> x > 0).count()양수의 개수를 카운트
max()Optional<T>스트림의 최대값 반환Stream.of(5, 3, 6, 2, 1).max(Integer::compareTo)스트림에서 최대값 6 반환
min()Optional<T>스트림의 최소값 반환strList.stream().min(String::compareToIgnoreCase)문자열 중 사전순 최소값 반환
findAny()Optional<T>스트림에서 임의의 요소 반환Stream.of(3,2,-5,6,-7).filter(x-> x< 0).findAny()음수 중 아무 값이나 반환
findFirst()Optional<T>스트림의 첫 번째 요소 반환Stream.of(-1,-4,6,2,1).filter(x->x>0).findFirst()양수 중 첫 번째 값 반환
allMatch()boolean모든 요소가 조건을 만족하는지 검사Stream.of(3, -4, 1, 0).allMatch(x -> x > 0)모든 요소가 양수인지 검사
anyMatch()boolean하나라도 조건을 만족하는지 검사Stream.of(1, 3, -4, 2).anyMatch(x -> x > 0)하나라도 양수가 있는지 검사
noneMatch()boolean모든 요소가 조건을 만족하지 않는지 검사list1.stream().noneMatch(num -> num % 2 == 0)모든 요소가 짝수가 아닌지 검사
reduce()Optional<T>요소를 하나로 줄이며 계산intList.stream().reduce((a,b) -> a+b)모든 요소의 합계 계산
collect()R요소를 수집하여 컬렉션 등으로 변환Stream.of(1, 2, 3, 4).collect(Collectors.toList())스트림을 리스트로 변환
  • forEach는 병렬 처리 시 순서를 보장하지 않지만, forEachOrdered는 순서를 보장

🙌 Collectors

Stream의 요소들을 수집하여 원하는 형태의 결과로 변환해주는 특별한 유틸리티

구분메서드설명
데이터 수집toList()Stream 요소들을 List로 변환
toSet()Stream 요소들을 Set으로 변환
toMap()Stream 요소들을 Map으로 변환
데이터 그룹화groupingBy()특정 기준으로 그룹화
partitioningBy()조건에 따라 두 그룹으로 분할
데이터 집계counting()요소 개수 계산
summingInt(), summingDouble()합계 계산
averagingInt(), averagingDouble()평균 계산
maxBy(), minBy()최대값, 최소값 찾기

REFERENCE
Hyun / Log 님의 TISTORY - Stream(스트림)이란? 사용법 총정리

profile
게시글 업로드중..⌛

0개의 댓글