[Java] Stream API

Jeini·2025년 9월 26일
0

☕️  Java

목록 보기
67/70
post-thumbnail

❗️ Stream API 문법을 익히고, 실전에 적용하여 코드를 가독성 & 안전성을 개선한다


📌 Stream API란?

✅ 함수형 프로그래밍을 도입하여 컬렉션, 배열 등을 처리/조작을 간단 효율적으로 하는 API

  • Java 8부터 도입된 기능
  • 데이터를 처리(필터링, 변환, 집계 등)하는 도구
  • 배열이나 컬렉션(List , Set 등)을 for문 을 안 돌리고도 깔끔하게 다룰 수 있게 해준다.

👉 핵심은 데이터를 “흐름(stream)”처럼 흘려보내면서 중간에 가공하고 최종 결과를 얻는 것이다.


📌 Stream의 특징

1. 선언형(Declarative)

  • for문 돌리면서 if 넣고… 하는 게 아니라, “필터링해”, “합계 구해” 처럼 무엇을 할지만 적으면 됨.

2. 내부 반복(Internal Iteration)

  • for-each 로 직접 돌리지 않고, Stream이 내부에서 알아서 반복 처리해줌.

3. 체이닝 가능(메서드 연속 호출)

  • 여러 개의 연산을 연결해서 파이프라인처럼 처리 가능.

4. 한 번 쓰면 재사용 불가

  • Stream은 일회성 → 필요하면 다시 만들어야 한다.

📌 Stream API를 쓰는 이유

1. 코드가 간결하고 가독성이 좋아짐 ✨

  • 기존 for문 방식:
List<String> list = Arrays.asList("java", "python", "c");
List<String> result = new ArrayList<>();
for (String s : list) {
    if (s.length() > 3) {
        result.add(s.toUpperCase());
    }
}
  • Stream 방식:
List<String> result = list.stream()
                          .filter(s -> s.length() > 3)
                          .map(String::toUpperCase)
                          .toList();

2. 데이터 처리 과정을 “파이프라인”처럼 표현 가능 🛠️

  • 여러 조건/연산을 연결(체이닝) 해서 깔끔하게 기술할 수 있다.
  • 예: 필터링 → 정렬 → 변환 → 집계까지 한 줄로 가능.

3. 병렬 처리(Parallel Stream) 지원 ⚡

  • .parallelStream() 을 쓰면 멀티코어 CPU를 활용해서 데이터 처리를 병렬로 실행할 수 있다.
  • 반복문으로는 직접 스레드를 짜야 하는데, Stream은 그냥 한 줄로 끝남:
list.parallelStream()
    .forEach(System.out::println);

4. 유지보수 & 협업에 유리 👥

  • Stream 코드 보면 의도가 바로 드러난다. (“필터링하고, 변환하고, 출력한다”)
  • for문은 “어떻게” 하는지 일일이 읽어야 해서 복잡하다.

5. 함수형 프로그래밍 스타일 지원 🧩

  • 람다(Lambda)랑 같이 쓰면 “데이터를 선언적으로 다루는” 코드 작성 가능.
  • 마치 SQL 쿼리처럼:
SELECT UPPER(name) FROM list WHERE LENGTH(name) > 3;

👉 이 느낌을 Java 코드로 가져온 게 Stream이다.


📌 Stream 처리 과정 (3단계)

1. 생성 (Create)

  • List , Set , 배열 등에서 .stream() 호출
List<String> names = Arrays.asList("정잉이", "철수", "영희");
Stream<String> stream = names.stream();

2. 중간 연산 (Intermediate Operations)

  • 데이터를 가공 (필터링, 변환, 정렬 등)
  • 대표적인 연산:
    filter() → 조건 걸러내기
    map() → 다른 형태로 변환
    sorted() → 정렬
    distinct() → 중복 제거

👉 중간 연산은 lazy (게으름) → 최종 연산이 실행돼야 동작한다!

3. 최종 연산 (Terminal Operation)

  • 결과를 내는 단계
  • 대표적인 연산:
    forEach() → 출력
    collect() → 다시 리스트/셋으로 모으기
    count() → 통계, 개수 세기
    sum() → 합계, 평균 등 집계
    reduce() → 소모, indentity(초기값)와 연산
    findFirst() → 검색, Stream의 첫번째 값 추출

✏️ 예제 코드 (1)

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

public class StreamExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("정잉이", "철수", "영희", "철수");

        // "철수" 빼고, 중복 제거해서, 대문자로 바꿔 출력
        names.stream()
             .filter(name -> !name.equals("철수"))   // 중간 연산 (필터링)
             .distinct()                            // 중복 제거
             .map(String::toUpperCase)              // 변환
             .forEach(System.out::println);         // 최종 연산 (출력)
    }
}
정잉이
영희

✏️ 예제 코드 (2)

  • for-loop 개선
// [기존 for-loop]
int[] numbers = {1, 2, 3, 4, 5};
int sum = 0;

for (int n : numbers) {
    sum += n;
}

System.out.println("합계: " + sum);

// [Stream으로 개선]
import java.util.stream.*;

int[] numbers = {1, 2, 3, 4, 5};
int sum = IntStream.of(numbers).sum();

System.out.println("합계: " + sum);

📌 Stream 3가지

1️⃣ Stream.of()

지정한 요소들을 바로 스트림으로 만들어 줌.

  • [주로 쓸 때]: 배열, 값들을 바로 스트림으로 만들고 싶을 때
  • [장점]: 배열이 아니더라도 바로 여러 값을 넣어서 스트림을 만들 수 있음.
  • [주의]: 스트림은 한 번만 쓸 수 있음 (재사용 X)
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("apple", "banana", "cherry");
        stream.forEach(System.out::println);
    }
}
apple
banana
cherry

2️⃣ Arrays.stream()

배열을 스트림으로 변환

  • [주로 쓸 때]: 이미 배열이 있는 경우
import java.util.Arrays;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};
        IntStream stream = Arrays.stream(numbers); // primitive int 배열도 가능
        stream.forEach(System.out::println);
    }
}
  • 배열뿐 아니라 부분 배열만 스트림으로 만들 수도 있음
Arrays.stream(numbers, 1, 4) // index 1~3 요소만

3️⃣ collection.stream()

List , Set 같은 컬렉션 객체에서 스트림 생성

  • [주로 쓸 때]: 이미 컬렉션에 데이터가 담겨 있을 때
  • [장점]: 컬렉션 자체에서 바로 스트림 생성 가능
  • parallelStream() 을 사용하면 병렬 스트림으로 처리 가능
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "banana", "cherry");
        list.stream().forEach(System.out::println);
    }
}

✅ 요약

메서드입력특징
Stream.of()여러 값, 배열직접 값 지정 가능, 간단하게 스트림 생성
Arrays.stream()배열배열 → 스트림 변환, 부분 배열 선택 가능
collection.stream()List, Set 등 컬렉션컬렉션 내부 데이터를 바로 스트림으로 처리 가능
profile
Fill in my own colorful colors🎨

0개의 댓글