[JAVA] Stream

handa·2024년 11월 25일
0
post-thumbnail

Java 스트림(Stream)은 Java 8에서 도입된 강력한 API로, 데이터를 선언적이고 간결하게 처리할 수 있도록 설계되었습니다. 스트림은 데이터 컬렉션(예: 리스트, 배열)을 처리하는 데이터 파이프라인으로 이해할 수 있습니다.

주요 특징

  • 선언적 프로그래밍

    스트림을 사용하면 명령형 프로그래밍(루프나 조건문) 대신 선언적 스타일로 데이터를 처리할 수 있습니다.

  • 중간 연산과 최종 연산

    스트림은 중간 연산(Intermediate Operation)과 최종 연산(Terminal Operation)으로 나뉩니다. 중간 연산은 스트림을 변환하거나 필터링하며, 최종 연산은 스트림을 닫고 결과를 반환합니다.

  • 지연 처리

    중간 연산은 필요할 때만 실행됩니다. 즉, 최종 연산이 호출될 때까지 실행되지 않습니다.

  • 불변성

    스트림 연산은 원본 데이터를 변경하지 않고 새로운 스트림을 생성합니다.

  • 단일 사용

    스트림은 한 번 사용되면 재사용할 수 없습니다.

스트림 생성

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        // 리스트에서 생성
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Stream<Integer> streamFromList = list.stream();

        // 배열에서 생성
        String[] array = {"a", "b", "c"};
        Stream<String> streamFromArray = Arrays.stream(array);

        // 숫자 범위에서 생성
        IntStream intStream = IntStream.range(1, 5); // 1, 2, 3, 4
        LongStream longStream = LongStream.rangeClosed(1, 5); // 1, 2, 3, 4, 5

        // 직접 생성
        Stream<String> directStream = Stream.of("one", "two", "three");

        // 빈 스트림 생성
        Stream<Object> emptyStream = Stream.empty();
    }
}

스트림 연산

1. 중간 연산 (Intermediate Operations)

중간 연산은 새로운 스트림을 반환합니다. 대표적인 중간 연산은 다음과 같습니다:

  • filter(): 조건에 맞는 요소만 필터링
  • map(): 각 요소를 변환
  • sorted(): 요소 정렬
  • distinct(): 중복 제거
  • limit(): 결과 스트림의 크기 제한
  • skip(): 처음 N개의 요소를 건너뜀
List<String> names = Arrays.asList("John", "Jane", "Doe", "Jane");

List<String> result = names.stream()
    .filter(name -> name.startsWith("J")) // J로 시작하는 이름 필터링
    .map(String::toUpperCase)            // 대문자로 변환
    .distinct()                          // 중복 제거
    .sorted()                            // 정렬
    .collect(Collectors.toList());       // 리스트로 변환

System.out.println(result); // [JANE, JOHN]

2. 최종 연산 (Terminal Operations)

최종 연산은 스트림을 닫고 결과를 반환합니다. 대표적인 최종 연산은 다음과 같습니다:

  • collect() : 결과를 리스트, 집합 등으로 수집
  • forEach() : 각 요소에 대해 작업 수행
  • count() : 요소 개수 반환
  • reduce() : 요소를 축소(예: 합계, 곱 등)
  • anyMatch(), allMatch(), noneMatch() : 조건 검사
  • findFirst(), findAny() : 첫 번째 또는 임의의 요소 반환
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

int sum = numbers.stream()
    .filter(n -> n % 2 == 0) // 짝수만 선택
    .reduce(0, Integer::sum); // 합계 계산

System.out.println(sum); // 6 (2 + 4)

numbers.stream().forEach(System.out::println); // 요소 출력

병렬 스트림

스트림은 병렬 처리를 지원합니다. 병렬 스트림은 데이터를 분리하여 멀티스레드로 작업을 처리합니다.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

numbers.parallelStream()
    .map(n -> n * n)
    .forEach(System.out::println); // 결과는 병렬 처리 순서로 출력

스트림의 장점

  1. 코드 간결성 : 복잡한 작업을 간단한 선언형 코드로 처리 가능.
  2. 가독성 : 데이터 처리 파이프라인을 명확히 표현.
  3. 병렬 처리 : 대규모 데이터 처리에 유리.
profile
진짜 해보자

0개의 댓글