[JAVA] 스트림(Stream)

이연우·2025년 7월 9일

TIL

목록 보기
6/100

⚙️ 스트림이란?

  • 데이터(컬렉션, 배열 등)의 요소들을 연속적으로 처리할 수 있는 추상화된 흐름

🔁 스트림의 특징

특징설명
선언형반복문 없이 무엇을 할지 선언적으로 표현
함수형 프로그래밍 지원람다와 함께 쓰며 간결한 코드 작성 가능
중간/최종 연산 분리연산을 체이닝하면서 최종 연산 전까지 실제 실행 X (지연 평가)
내부 반복개발자가 반복을 구현하지 않고 스트림이 대신 처리
불변성스트림을 사용해도 원래의 컬렉션은 변경되지 않음

스트림의 기본 구조

list.stream()             		   // 🔹 스트림 생성
    .filter(x -> x > 0)   		   // 🔸 중간 연산 (조건 필터링
    .map(x -> x * 2)      		   // 🔸 중간 연산 (값 변경)
    .forEach(System.out::println); // 🔸 최종 연산 (출력)

🧵 스트림을 사용하여 각 요소를 10배로 변환 후, 리스트로 변환하는 예제

  • stream()map()collect() 순으로 데이터 흐름 처리
    stream(): 데이터 준비 - 데이터를 스트림으로 변환하여 연산 흐름을 만들 준비를 함
    map(): 중간 연산 등록 - 각 요소를 주어진 함수에 적용해서 변환
    collect(): 최종 연산 - 결과를 원하는 형태(List, Set)로 수집
  • 반복문 없이 간결하게 데이터 변환 가능

🗒️ 예시 코드:

// 1. 데이터 준비: 스트림 생성
Stream<Integer> stream = arrayList.stream();

// 2. 중간 연산 등록: 각 요소를 10배로 변환 로직 등록
Stream<Integer> mappedStream = stream.map(num -> num * 10);

// 3. 최종 연산: 최종 결과 리스트로 변환
List<Integer> ret2 = mappedStream.collect(Collectors.toList());
// ✅ 한 줄로 표현 가능
List<Integer> ret2 = arrayList.stream() // 1. 데이터 준비
    .map(num -> num * 10)               // 2. 중간 연산 등록
    .collect(Collectors.toList());  // 3. 최종 연산

⚠️ 스트림 사용 시 주의 사항

항목설명
스트림은 1회용한 번 사용하면 재사용 불가 ❌
중간 연산만으론 실행 안 됨최종 연산이 있어야 실행됨
순서를 보장해야 한다면 forEachOrdered() 사용병렬 스트림에서 유용
원본 컬렉션은 변하지 않음스트림은 불변 데이터 처리에 적합

📝 스트림과 람다식 활용

  • 스트림과 람다식을 함께 사용해서 각 요소 * 10 예시 작성 → map() 활용

1. 익명 클래스를 변수에 담아 활용

public class Main {

    public static void main(String[] args) {

        // ArrayList 선언
        List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));

        // ✅ 1. 익명클래스를 변수에 담아 활용
        Function<Integer, Integer> function = new Function<>() {

            @Override
            public Integer apply(Integer integer) {
                return integer * 10;
            }
        };
        
        List<Integer> ret3 = arrayList.stream()
                .map(function)
                .collect(Collectors.toList());
        System.out.println("ret3 = " + ret3);
    }
}

2. 람다식을 변수로 활용

public class Main {

    public static void main(String[] args) {

        // ArrayList 선언
        List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));

        // ✅ 2. 람다식을 변수에 담아 활용
        Function<Integer, Integer> functionLambda = (num -> num * 10);
        List<Integer> ret4 = arrayList.stream()
                .map(functionLambda)
                .collect(Collectors.toList());
        System.out.println("ret4 = " + ret4);
    }
}

3. 람다식을 매개변수에 직접 활용

public class Main {

    public static void main(String[] args) {

        // ArrayList 선언
        List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));

        // ✅ 3. 람다식을 직접 활용
        List<Integer> ret5 = arrayList.stream()
                .map(num -> num * 10)
                .collect(Collectors.toList());
        System.out.println("ret5 = " + ret5);
    }
}

✏️ 연습 문제) filter를 람다식으로 활용해 보기

  • 익명 클래스 활용
  • 람다식 만들기
  • 직접 람다식 대입
package chapter3_6;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {

        List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3, 4, 5));

        // 1. 익명 클래스 활용
        Predicate<Integer> predicate = new Predicate<>() {
            @Override
            public boolean test(Integer integer) {
                return (integer % 2 == 0);
            }
        };

        // 2. 람다식 만들기
        Predicate<Integer> filterLambda = (num -> num % 2 == 0);

        // 3.직접 람다식 대입
        List<Integer> ret3 = arrayList.stream().filter(num -> num % 2 == 0).collect(Collectors.toList());

        List<Integer> ret1 = arrayList.stream().filter(predicate).collect(Collectors.toList());
        List<Integer> ret2 = arrayList.stream().filter(filterLambda).collect(Collectors.toList());

        System.out.println("ret1 = " + ret1);
        System.out.println("ret2 = " + ret2);
        System.out.println("ret3 = " + ret3);
    }
}

0개의 댓글