본문 바로가기

Develop/Back-End

[Java] 스트림(Stream) API 사용 방법 / 외부반복 내부반복 차이점

<image by toptal>

Java 개발자라면 한번쯤 Stream API 에 대해서 들어보게 될 텐데 

회사 *코드 컨벤션에 따라 익숙한 개발자들도 있을 것이고 

사용을 아예 안하는 개발자도 많을 것 같은데🤪

 

나도 자바에선 자주 사용하지 않아 손에 익진 않았는데

사용하면서 퍼포먼스 측면에서도 나아지고 코드도 훨씬 간결해진듯... 😛

 

* 코드 컨벤션 (Code Convention) : 읽고 관리하기 쉬운 코드를 작성하기 위한 일종의 코딩 스타일 규약(하나의 작성 표준)

 

스트림이 무엇인지

간단하게 특징과 사용 방법을 블로그에 정리해보려고 해 😏

 


스트림 API는 자바 8부터 추가된 기능이야. 이걸 쓰면 컬렉션 처리가 훨씬 쉬워지고 성능도 높아져. 반복문을 직접 안 써도 되니까 코드도 간결해지고 가독성도 좋아져.

스트림은 데이터 처리를 파이프라인으로 생각하면 돼. 중간 연산과 최종 연산으로 구성돼 있는데, 중간 연산은 데이터를 필터링하거나 변환하는 작업을 하고, 최종 연산은 처리 결과를 얻어내는 작업을 하는 거야.

스트림 API를 사용하면 코드가 짧아지고 병렬 처리도 자동으로 지원되어 멀티코어 CPU를 효율적으로 활용할 수 있어. 

그래서 데이터 처리를 빠르고 간편하게 할 수 있고 성능도 좋아지는거지.

간단한 예시를 보여줄게. 😄

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

public class StreamApiExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Emma");

        // 이름이 4글자 이상인 요소만 필터링하여 새로운 리스트 생성
        List<String> longNames = names.stream()
                .filter(name -> name.length() >= 4)
                .toList();

        System.out.println("4글자 이상인 이름들: " + longNames);

        // 각 이름을 대문자로 변환하여 새로운 리스트 생성
        List<String> upperCaseNames = names.stream()
                .map(String::toUpperCase)
                .toList();

        System.out.println("대문자로 변환된 이름들: " + upperCaseNames);

        // 모든 이름을 하나의 문자열로 합치기
        String allNames = names.stream()
                .reduce((name1, name2) -> name1 + ", " + name2)
                .orElse("");

        System.out.println("모든 이름: " + allNames);
    }
}


이렇게 스트림 API를 사용하면 데이터 처리가 편리해지고 성능까지 개선될 수 있어. 🚀

글 가장 하단 참고 영역에 오라클 Document 링크도 남겨놓았으니

어떤 메소드들이 있는지 보는것도 도움이 많이 될거야! 나도 잘 몰라서 즐겨찾기 해놓고 봐야되고..😵


내부반복과 외부반복 🚧

1. 내부반복 (Internal Iteration):

내부반복은 Stream API가 컬렉션의 요소를 내부적으로 처리하는 방식으로, 개발자는 요소 반복을 명시적으로 작성하지 않아. 이를 통해 개발자는 데이터 처리에 집중할 수 있지

장점:
- 간결하고 가독성이 높은 코드 작성이 가능
- 병렬 처리를 자동으로 지원하므로 멀티코어 CPU에서 병렬 실행 활용

단점:
- 커스텀 반복 로직을 작성하기 어렵거나 제약이 있음
- 간혹 복잡한 연산에서는 성능이 약간 저하

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

// 내부반복으로 짝수인 숫자들을 필터링하여 총합 구하기
int sumOfEvenNumbers = numbers.stream()
        .filter(number -> number % 2 == 0)
        .mapToInt(Integer::intValue)
        .sum();

System.out.println("짝수의 합: " + sumOfEvenNumbers);



2. 외부반복 (External Iteration):

외부반복은 기존의 반복문을 사용하여 개발자가 직접 컬렉션의 요소를 반복하는 방식이야. 

개발자가 반복 로직을 명시적으로 작성해야해.

장점:
- 커스텀 반복 로직을 자유롭게 작성할 수 있음
- 코드의 동작을 직접 제어하고 디버깅하기 쉬움

단점:
- 코드가 비교적 길고 복잡해질 수 있음
- 병렬 처리를 구현하기 어려우며, 멀티코어 CPU의 성능을 최대한 활용하기 어려움

예시:

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

// 외부반복으로 짝수인 숫자들을 필터링하여 총합 구하기
int sumOfEvenNumbers = 0;
for (Integer number : numbers) {
    if (number % 2 == 0) {
        sumOfEvenNumbers += number;
    }
}

System.out.println("짝수의 합: " + sumOfEvenNumbers);



결론적으로, 내부반복은 간결하고 성능 개선을 기대할 수 있고 😄,

반면 외부반복은 커스텀 로직 작성이 자유롭고 직관적인 디버깅이 가능해

선택은 개발 상황과 선호에 따라 달라질 수 있고,

Stream API를 잘 활용하면 더 간결하고 효율적인 코드를 작성할 수 있을거야 

잘 활용하면!!! 🤨

 

 


참고 레퍼런스

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

 

java.util.stream (Java Platform SE 8 )

Interface Summary  Interface Description BaseStream > Base interface for streams, which are sequences of elements supporting sequential and parallel aggregate operations. Collector A mutable reduction operation that accumulates input elements into a mutab

docs.oracle.com

https://www.baeldung.com/java-8-streams-introduction

 

The Baeldung

Introduction to Java 8 Streams

www.baeldung.com

 

반응형