Java Stream 공부 정리

키요·2025년 8월 31일

공부

목록 보기
14/32

1. Stream이란?

  • 배열, 컬렉션(List, Set 등)의 데이터를 흐름(스트림) 으로 다루는
    API
  • for문 대신 선언적 방식으로 데이터를 가공, 필터링, 집계 가능
  • "데이터 → (map) → (filter) → (collect)" 파이프라인 처리 구조

2. Stream의 특징

  1. 원본 불변: 스트림은 원본을 건드리지 않음
  2. 일회성: 한 번 사용하면 다시 사용할 수 없음
  3. 내부 반복: for문 대신 내부적으로 반복
  4. 지연 연산: 중간 연산은 실행되지 않고, 종단 연산 때 실행

3. Stream 연산 구조

  • 중간 연산 (Intermediate) → Stream 반환 (계속 붙일 수 있음)
    • map, mapToInt, mapToDouble, filter, sorted,
      distinct, limit, skip, peek, flatMap
  • 종단 연산 (Terminal) → 결과 반환 (Stream 종료)
    • forEach, forEachOrdered, collect, reduce, sum,
      count, average, min, max, anyMatch, allMatch,
      noneMatch, findFirst, findAny

4. 주요 메서드 예시

map / mapToInt / mapToDouble

값 변환 (문자열 → 숫자, 숫자 → 제곱 등)

Arrays.stream(new String[]{"1","2","3"})
      .mapToInt(Integer::parseInt)
      .forEach(System.out::println);
// 1 2 3

filter

조건 통과한 값만 남기기

IntStream.range(1, 10)
         .filter(n -> n % 2 == 0)
         .forEach(System.out::println);
// 2 4 6 8

sorted / distinct

Stream.of(5, 1, 2, 5, 3)
      .distinct()
      .sorted()
      .forEach(System.out::println);
// 1 2 3 5

limit / skip

IntStream.rangeClosed(1, 10)
         .skip(3)
         .limit(4)
         .forEach(System.out::println);
// 4 5 6 7

forEach / forEachOrdered

Stream.of("A","B","C").forEach(System.out::println); 
// 순서 보장X (병렬일 경우)
// A B C

Stream.of("A","B","C").forEachOrdered(System.out::println);
// 순서 보장
// A B C

reduce

누적 처리

int sum = IntStream.of(1,2,3,4).reduce(0, (a,b) -> a+b);
// 10

collect

컬렉션/문자열로 수집

List<String> list = Stream.of("a","b","c").collect(Collectors.toList());
String joined = Stream.of("a","b","c").collect(Collectors.joining(","));
// joined = "a,b,c"

match 계열 (anyMatch / allMatch / noneMatch)

boolean anyEven = IntStream.of(1,3,5,8).anyMatch(n -> n % 2 == 0); // true
boolean allEven = IntStream.of(2,4,6).allMatch(n -> n % 2 == 0);   // true
boolean noneNegative = IntStream.of(1,2,3).noneMatch(n -> n < 0);  // true

findFirst / findAny

OptionalInt first = IntStream.range(1, 10).findFirst(); // 1
OptionalInt any = IntStream.range(1, 10).findAny();     // (병렬 시 임의 값)

peek

중간 과정 디버깅

Stream.of("a","b","c")
      .peek(s -> System.out.println("DEBUG: " + s))
      .map(String::toUpperCase)
      .forEach(System.out::println);

5. Optional과 orElse / orElseThrow

  • Stream의 종단 연산 결과가 없을 수 있어서 Optional 사용
  • orElse(default) : 값이 없으면 기본값 반환
  • orElseThrow() : 값이 없으면 예외 발생
int max = IntStream.empty().max().orElse(-1);
int mustMax = IntStream.empty().max().orElseThrow();

6. 박싱/언박싱 성능 이슈

  • int ↔ Integer 변환 시 성능 저하 (박싱/언박싱 오버헤드)
  • 해결: 원시 타입 스트림(IntStream, LongStream, DoubleStream) 사용

7. Stream vs for문

구분 Stream for문


가독성 선언적, 파이프라인 직관적, 단순
성능 오버헤드 있음 기본형 직접 연산
제어 break/continue 불편 제어문 쉬움
병렬 처리 .parallelStream() 가능 직접 구현 필요


8. 삼항연산자 사용 가능

List<Integer> nums = List.of(10, 15, 20);
nums.stream()
    .map(n -> n % 2 == 0 ? n * 2 : n * 3)
    .forEach(System.out::println);
// 20 45 40

✅ 최종 정리

  • Stream = 데이터 처리 파이프라인
  • 중간 연산: Stream 반환, 체인 가능
  • 종단 연산: 결과 반환, Stream 종료
  • Optional로 안전하게 결과 처리
  • 성능 위해 IntStream/DoubleStream 권장
  • 상황에 따라 for문과 혼용
profile
운도 실력

0개의 댓글