어제 오늘 내일

[Java] Stream API 기초와 예제 본문

IT/Java

[Java] Stream API 기초와 예제

hi.anna 2026. 1. 3. 01:16

Java의 Stream API는 컬렉션이나 배열의 요소를
선언적(Declarative)이고 간결한 방식으로 처리할 수 있도록 도와주는 기능입니다.
반복문 없이도 데이터를 필터링, 변환, 집계할 수 있어 코드 가독성과 생산성이 크게 향상됩니다.

Stream은 Java 8에서 추가된 기능이며, “데이터 흐름”을 한 번 흘려보내며 처리하는 구조라고 이해하면 쉽습니다.

 

1. Stream이란?

Stream은 데이터 컬렉션을 다루기 위한 연속된 작업 흐름입니다.
특징은 다음과 같습니다.

  • 데이터를 변경하지 않음 (원본 불변)
  • 중간 연산(filter, map 등)과 최종 연산(sum, collect 등)으로 구성
  • 내부 반복(Internal Iteration)을 사용해 반복문을 자동 처리
  • 작업을 체이닝하여 선언적으로 작성

예:

list.stream()
    .filter(...)
    .map(...)
    .collect(...)

 

 

2. Stream 생성하기

2-1. 리스트에서 Stream 생성

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();

2-2. 배열에서 Stream 생성

int[] arr = {1, 2, 3};
IntStream stream = Arrays.stream(arr);

2-3. 정적 메서드로 생성

Stream<Integer> stream = Stream.of(1, 2, 3, 4);

 

 

3. Stream 중간 연산 (Intermediate Operation)

중간 연산은 스트림을 변환하거나 필터링하며, 새로운 스트림을 반환합니다.
최종 연산이 실행되기 전까지는 실제로 동작하지 않는 지연(lazy) 처리 방식입니다.

3-1. filter() – 조건에 맞는 요소만 추출

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

nums.stream()
    .filter(n -> n % 2 == 0)
    .forEach(System.out::println); // 2, 4

3-2. map() – 요소 변환

List<String> list = Arrays.asList("a", "b", "c");

list.stream()
    .map(s -> s.toUpperCase())
    .forEach(System.out::println); // A, B, C

3-3. sorted() – 정렬

nums.stream()
    .sorted()
    .forEach(System.out::println);

3-4. distinct() – 중복 제거

List<Integer> list = Arrays.asList(1, 2, 2, 3);

list.stream()
    .distinct()
    .forEach(System.out::println); // 1, 2, 3

 

 

4. Stream 최종 연산 (Terminal Operation)

최종 연산은 스트림을 소모하며 결과를 만듭니다.

4-1. forEach() – 반복 처리

list.stream().forEach(System.out::println);

4-2. collect() – 컬렉션으로 변환

List<Integer> evenList = nums.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.toList());

4-3. count() – 개수 반환

long count = nums.stream().count();

4-4. sum(), average() – 숫자 스트림 전용

int sum = nums.stream()
    .mapToInt(n -> n)
    .sum();

4-5. findFirst(), findAny()

Optional<Integer> first = nums.stream().findFirst();

 

 

5. Stream 파이프라인 예제

예제: 문자열 리스트에서 길이가 3 이상인 문자열만 대문자로 변환 후 출력

List<String> list = Arrays.asList("a", "java", "hi", "stream");

list.stream()
    .filter(s -> s.length() >= 3)
    .map(String::toUpperCase)
    .forEach(System.out::println);

출력:

JAVA
STREAM

설명

  • filter로 길이 조건 적용
  • map으로 대문자 변환
  • forEach로 출력

 

6. Stream을 사용하는 이유

✔ 코드가 깔끔하고 선언적

복잡한 for문이 사라짐

✔ 병렬 처리(parallelStream)가 쉬움

멀티코어 활용 가능

✔ 다양한 데이터 처리 연산 제공

필터링, 변환, 정렬, 집계 등 풍부한 기능 제공

✔ NullPointerException 줄이고 안전한 코드 작성 가능

함수형 스타일과 Optional과 함께 사용할 때 특히 강력

 

7. 전체 예제: 사용자 리스트에서 특정 조건 필터링

class User {
    String name;
    int age;
    User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

List<User> users = Arrays.asList(
    new User("Tom", 20),
    new User("Alice", 30),
    new User("Bob", 25)
);

List<String> names = users.stream()
    .filter(u -> u.age > 20)
    .map(u -> u.name)
    .collect(Collectors.toList());

System.out.println(names); // [Alice, Bob]

 

 

8. 정리

  • Stream은 데이터를 선언적으로 처리하는 Java 8 기능
  • 중간 연산(filter, map, sorted)과 최종 연산(forEach, collect 등)으로 구성
  • 원본 데이터를 변경하지 않음
  • 복잡한 로직도 간결하게 표현 가능

 

 

반응형
Comments