스트림(Stream)이란 무엇인가

스트림은 자바 8에서 도입된 기능으로 컬렉션(Collection)과 같은 데이터 소스를 함수형 프로그래밍 방식으로 처리할 수 있도록 도와주는 API 이걸 사용해 데이터를 필터링, 매핑, 정렬, 집계 등 빠르고 직관적으로 수행가능

 

컬렉션(Collection) 인터페이스에 디폴트(Default) 메서드로 stream()이 정의돼있는데 이 메서드를 사용해서 해당 컬렉션의 데이터 흐름인 Stream을 만들 수 있다.

 

List<String> list = Arrays.asList("apple", "banana", "orange");

// 컬렉션을 스트림으로 변환하여 각 요소를 출력
list.stream().forEach(System.out::println);  // apple, banana, orange 출력

 

스트림의 특징 3가지

1. 지연 연산: 중간연산은 지연연산, 최종연산이 호출 전까지는 데이터를 처리하지 않는다.

     -> 성능 최적화

2. 일회성: 만들어진 스트림은 한 번의 연산 후 더 이상 사용할 수 없다.

     -> 그래서 일반적으로 set.stream()으로 변수에 넣지 않고 바로 사용

3. 순차 또는 병렬 처리: 순차 처리 기본, parallelStream()을 통해 병렬 스트림 생성하여 동시에 처리 가능

 

스트림 연산 종류

1. 중간 연산(Intermediate Operations)

중간 연산은 스트림 변형, 필터링 연산

- filter(): 조건에 맞는 요소만 남기기

- map(): 각 요소 다른 형태로 변환

- sorted(): 요소 정렬

- distinct(): 중복제거

 

2. 최종연산 (Terminal Operation)

스트림의 연산을 완료하고 결과 반환, 이 이후 해당 스트림은 사용 불가(일회성)

- forEach(): 각 요소에 대해 작업 수행

- collect(): 스트림을 컬렉션이나 다른 형태로 변환

- reduce(): 스트림 요소를 하나로 합침

 

스트림 장점

- 간결한 코드: 복잡한 반복문 대신 간결한 함수형 코드 작성 가능

- 함수형 프로그래밍 지원: filter(), map(), reduce() 같은 연산을 통해 데이터를 선언적 처리

- 병렬 처리: 병렬 스트림을 통해 빠르게 처리

 

외부 반복 VS 내부 반복

외부 반복: for, while 과 같은 원래 쓰던 반복

내부 반복: 스트림을 사용하여 데이터를 처리하는 방식 데이터의 순회와 처리는 스트림에서 처리

 

차이점 요약

1. 제어권의 차이

외부: 개발자가 반복 설계

내부: 스트림이 알아서, 처리 로직만 제공하면 됨

2. 코드의 간결함

외부: 코드 장황

내부: 간결

3. 병렬 처리

외부: 스레드 관리 수동관리

내부: 병렬 스트림 통해 병렬처리 간편

 

연습코드

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        // 리스트 초기화
        List<String> fruits = Arrays.asList("apple", "banana", "avocado", "grape", "orange");

        // 1. 'a'로 시작하는 문자열 필터링
        // 2. 각 문자열을 대문자로 변환
        // 3. 결과를 알파벳 순으로 정렬
        // 4. 결과를 리스트로 수집
        List<String> result = fruits.stream()               // 스트림 생성
                                    .filter(s -> s.startsWith("a")) // 'a'로 시작하는 문자열 필터링
                                    .map(String::toUpperCase)       // 대문자로 변환
                                    .sorted()                      // 정렬
                                    .collect(Collectors.toList());  // 리스트로 수집

        // 결과 출력
        System.out.println(result);  // [APPLE, AVOCADO]

        // 숫자 리스트 초기화
        List<Integer> numbers = Arrays.asList(1, 2, 3, 3, 4, 5, 6);

        // 1. 중복된 값 제거 (distinct)
        // 2. 3보다 큰 숫자만 필터링
        // 3. 처음 2개를 제외하고 나머지를 출력
        numbers.stream()
               .distinct()               // 중복 제거
               .filter(n -> n > 3)       // 3보다 큰 숫자 필터링
               .skip(2)                  // 처음 2개를 건너뛰기
               .forEach(System.out::println);  // 결과 출력: 6

        // 숫자 합계 계산
        int sum = numbers.stream()
                         .reduce(0, Integer::sum);  // 스트림 요소의 합 계산
        System.out.println("Sum: " + sum);  // 합계 출력: Sum: 24
    }
}

+ Recent posts