본문 바로가기
won2dev-log
HomeArchiveTagsCategoriesAboutProjects
HomeArchiveTagsCategoriesAboutProjects
won2dev-logwon2dev-logwon2dev-log

비전공 개발자의 로그 | won2dev-log

Navigation
  • Home
  • Archive
  • About
  • Projects
Categories
  • Docs
  • TIL
  • Automation
  • Git · GitHub
  • Project
Tags
  • TIL
  • Java
  • Spring
  • Backend
  • n8n
더보기
About

기록을 거름 삼아 공유는 성장을 만든다.

LicensePrivacy
© won2dev 2026. All rights reserved.
Home›Docs›TIL - Java 기초: 스트림(Stream)으로 데이터 다루기
Docs

TIL - Java 기초: 스트림(Stream)으로 데이터 다루기

won2dev·2025년 03월 21일
#Java#TIL
TIL - Java 기초: 스트림(Stream)으로 데이터 다루기

💬 배운 기술 / 지식

  • 스트림(Stream)의 개념과 특징
  • 스트림 생성 방법
  • 중간 연산과 최종 연산
  • 대표적인 스트림 연산 메서드 (filter, map 포함)
  • 병렬 스트림(Parallel Stream)
  • 스트림의 장점과 주의사항

🔥 스트림(Stream)이란?

  • Java 8부터 도입된 데이터 소스를 추상화해 연속적인 요소들을 처리할 수 있는 기능
  • 내부 반복과 함수형 스타일 코딩 지원
  • 원본 데이터(컬렉션, 배열 등)를 변경하지 않고, 처리 결과를 얻음
  • 읽기 전용이며, 연산은 지연(lazy) 처리됨

🚀 스트림 생성 방법

  • 컬렉션에서 스트림 생성
java
List<String> list = Arrays.asList("Java", "Python", "C++");
Stream<String> stream = list.stream();
List<String> list = Arrays.asList("Java", "Python", "C++");
Stream<String> stream = list.stream();
  • 배열에서 스트림 생성
java
Stream<Integer> intStream = Arrays.stream(new Integer[]{1, 2, 3, 4});
Stream<Integer> intStream = Arrays.stream(new Integer[]{1, 2, 3, 4});
  • 직접 스트림 생성
java
Stream<String> stream = Stream.of("a", "b", "c");
Stream<String> stream = Stream.of("a", "b", "c");

🔄 중간 연산 (Intermediate Operations)

  • 스트림의 데이터를 변환하거나 필터링하는 연산
  • 여러 개 연결 가능(연쇄 호출)
  • 최종 연산 전까지는 실제 동작하지 않음 (지연 실행)

1️⃣ filter (필터)

  • 조건에 맞는 요소만 걸러내는 역할
  • 각 요소를 검사해 true인 요소만 다음 단계로 전달
  • 불필요한 데이터 제외로 효율적인 처리 가능
java
.filter(element -> 조건식)
.filter(element -> 조건식)

예제: "J"로 시작하는 문자열만 필터링

java
List<String> languages = Arrays.asList("Java", "Python", "JavaScript", "C++");
languages.stream()
         .filter(s -> s.startsWith("J"))  // 'J'로 시작하는 요소만 통과
         .forEach(System.out::println);   // 출력: Java, JavaScript
List<String> languages = Arrays.asList("Java", "Python", "JavaScript", "C++");
languages.stream()
         .filter(s -> s.startsWith("J"))  // 'J'로 시작하는 요소만 통과
         .forEach(System.out::println);   // 출력: Java, JavaScript

2️⃣ map (맵)

  • 스트림의 각 요소를 다른 형태로 변환하는 역할
  • 입력 요소 하나를 받아 변환 후 결과를 다음 단계에 넘김
  • 문자열 대문자 변환, 객체 필드 추출 등 다양하게 활용 가능
java
.map(element -> 변환식)
.map(element -> 변환식)

예제: 문자열을 대문자로 변환

java
List<String> fruits = Arrays.asList("apple", "banana", "orange");
fruits.stream()
      .map(String::toUpperCase)       // 모든 문자열을 대문자로 변환
      .forEach(System.out::println);  // 출력: APPLE, BANANA, ORANGE
List<String> fruits = Arrays.asList("apple", "banana", "orange");
fruits.stream()
      .map(String::toUpperCase)       // 모든 문자열을 대문자로 변환
      .forEach(System.out::println);  // 출력: APPLE, BANANA, ORANGE

filter 와 map 함께 사용하기

java
List<String> languages = Arrays.asList("Java", "Python", "JavaScript", "C++");

languages.stream()
         .filter(s -> s.startsWith("J"))   // 'J'로 시작하는 요소만 필터링
         .map(String::toUpperCase)         // 대문자로 변환
         .forEach(System.out::println);    // 출력: JAVA, JAVASCRIPT
List<String> languages = Arrays.asList("Java", "Python", "JavaScript", "C++");

languages.stream()
         .filter(s -> s.startsWith("J"))   // 'J'로 시작하는 요소만 필터링
         .map(String::toUpperCase)         // 대문자로 변환
         .forEach(System.out::println);    // 출력: JAVA, JAVASCRIPT

주요 중간 연산 메서드

메서드설명예시
filter조건에 맞는 요소만 필터링.filter(s -> s.startsWith("J"))
map요소를 다른 형태로 변환.map(String::toUpperCase)
sorted정렬.sorted()
distinct중복 제거.distinct()
limit개수 제한.limit(3)

🎯 최종 연산 (Terminal Operations)

  • 스트림 처리 결과를 만들거나 부수 효과 발생시키는 연산
  • 스트림 파이프라인 종료, 이후 스트림은 사용 불가

주요 최종 연산 메서드

메서드설명예시
forEach각 요소에 동작 수행.forEach(System.out::println)
collect결과를 컬렉션 등으로 모음.collect(Collectors.toList())
count요소 개수 반환.count()
reduce누적 연산 수행.reduce((a, b) -> a + b)
anyMatch조건에 맞는 요소 존재 여부 확인.anyMatch(s -> s.contains("a"))

📝 예제 1: 필터링과 출력

java
import java.util.Arrays;
import java.util.List;

public class StreamExample1 {
    public static void main(String[] args) {
        List<String> languages = Arrays.asList("Java", "Python", "JavaScript", "C++", "Ruby");

        // "J"로 시작하는 언어만 필터링 후 출력
        languages.stream()
                 .filter(s -> s.startsWith("J"))  // 조건에 맞는 요소만 선택
                 .forEach(System.out::println);   // 출력
    }
}
import java.util.Arrays;
import java.util.List;

public class StreamExample1 {
    public static void main(String[] args) {
        List<String> languages = Arrays.asList("Java", "Python", "JavaScript", "C++", "Ruby");

        // "J"로 시작하는 언어만 필터링 후 출력
        languages.stream()
                 .filter(s -> s.startsWith("J"))  // 조건에 맞는 요소만 선택
                 .forEach(System.out::println);   // 출력
    }
}

📝 예제 2: 대문자 변환 후 리스트로 수집

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

public class StreamExample2 {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "orange", "apple");

        // 중복 제거, 대문자로 변환 후 리스트로 수집
        List<String> result = fruits.stream()
                                    .distinct()                 // 중복 제거
                                    .map(String::toUpperCase)  // 대문자 변환
                                    .collect(Collectors.toList()); // 결과 리스트 생성

        System.out.println(result); // [APPLE, BANANA, ORANGE]
    }
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample2 {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "orange", "apple");

        // 중복 제거, 대문자로 변환 후 리스트로 수집
        List<String> result = fruits.stream()
                                    .distinct()                 // 중복 제거
                                    .map(String::toUpperCase)  // 대문자 변환
                                    .collect(Collectors.toList()); // 결과 리스트 생성

        System.out.println(result); // [APPLE, BANANA, ORANGE]
    }
}

📝 예제 3: 숫자 합계 구하기 (reduce)

java
import java.util.Arrays;
import java.util.List;

public class StreamExample3 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 모든 숫자 더하기
        int sum = numbers.stream()
                         .reduce(0, (a, b) -> a + b);

        System.out.println("합계: " + sum); // 합계: 15
    }
}
import java.util.Arrays;
import java.util.List;

public class StreamExample3 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 모든 숫자 더하기
        int sum = numbers.stream()
                         .reduce(0, (a, b) -> a + b);

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

⚙️ 병렬 스트림(Parallel Stream)

  • 데이터를 여러 쓰레드에서 병렬 처리해 성능 향상 가능
  • 사용법은 간단, .parallelStream() 사용
java
int sum = numbers.parallelStream()
                 .reduce(0, Integer::sum);
int sum = numbers.parallelStream()
                 .reduce(0, Integer::sum);
  • 단, 병렬 처리 시 상태 변경하는 부수효과는 주의 필요

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

  • 스트림은 1회용: 최종 연산 후 재사용 불가
  • 부수 효과(외부 상태 변경) 최소화 권장
  • 너무 복잡한 파이프라인은 오히려 가독성 떨어질 수 있음
  • 병렬 처리 시 공유 자원 동기화 주의

💡 느낀 점 / 참고 사항

  • 스트림 덕분에 데이터 처리 코드가 더 간결하고 명확해짐
  • 함수형 프로그래밍 패러다임에 익숙해질 수 있는 좋은 출발점
  • 컬렉션과 함께 활용하면 데이터 변환, 필터링, 집계 등 다양한 작업 손쉽게 가능
  • 초보자도 반복문 대신 스트림 사용법을 차근차근 익히면 생산성 향상
공유하기
이전 글TIL - Java 기초: 쓰레딩 시작하기다음 글 TIL - Java 기초: 람다 표현식(Lambda Expression) 시작하기

목차

  • 💬 배운 기술 / 지식
  • 🔥 스트림(Stream)이란?
  • 🚀 스트림 생성 방법
  • 🔄 중간 연산 (Intermediate Operations)
  • 1️⃣ filter (필터)
  • 예제: "J"로 시작하는 문자열만 필터링
  • 2️⃣ map (맵)
  • 예제: 문자열을 대문자로 변환
  • filter 와 map 함께 사용하기
  • 주요 중간 연산 메서드
  • 🎯 최종 연산 (Terminal Operations)
  • 📝 예제 1: 필터링과 출력
  • 📝 예제 2: 대문자 변환 후 리스트로 수집
  • 📝 예제 3: 숫자 합계 구하기 (reduce)
  • ⚙️ 병렬 스트림(Parallel Stream)
  • ⚠️ 스트림 사용 시 주의사항
  • 💡 느낀 점 / 참고 사항

카테고리

Docs

태그

#Java#TIL

최근 글

Git 요약 (1) - Rebase, Stash, Squash MergeTIL - MSA 핵심 요소 정리TIL - (4) Spring 어노테이션 정리: Mockito를 활용한 단위 테스트TIL - (3) Spring 어노테이션 정리: Lombok Getter, Setter와 생성자TIL - (2) Spring MVC와 WebFlux의 차이: 블로킹과 논블로킹