공부/JAVA

[Java] 스트림 - 핵심 개념과 특징

raptorhs 2024. 7. 8. 10:26

스트림(Stream)은 배열, 컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자입니다.

 

학습 목표

  • 스트림의 핵심적인 개념과 특징을 이해할 수 있다.
  • 스트림의 생성, 중간 연산, 최종 연산의 세 단계로 구성된 스트림 파이프라인을 이해하고 활용할 수 있다.
  • 스트림의 주요 메서드를 활용해 원하는 데이터 처리를 할 수 있다.

 

스트림의 핵심 개념과 특징

자바에서의 스트림은 “데이터의 흐름”을 의미합니다. 좀 더 구체적으로, 각 데이터를 흐름에 따라 우리가 원하는 결과로 가공하고 처리하는 일련의 과정과 관련이 있습니다.

 

스트림(Stream)의 도입 배경

for문과 Iterator를 사용하는 경우, 코드가 길고 복잡해 질 수 있습니다.

  • Iterator를 사용한 반복 처리
package Stream;

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

public class PrintNumberOperator {
    public static void main(String[] args) {
        // 각 숫자를 배열화
        List<Integer> list = Arrays.asList(1,2,3,4,5);

        //Iterator 생성
        Iterator<Integer> it = list.iterator();

        //리스트를 순회하며 값 출력
        while (it.hasNext()){
            int num = it.next();
            System.out.print(num);
        }
    }
}

 

같은결과를 스트림을 사용하여 작성하는 코드입니다.

  • 스트림을 사용한 반복 처리
package Stream;

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

public class PrintNumberOperatorByStream {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        Stream<Integer> stream = list.stream();
        stream.forEach(System.out::println);
    }
}

 

스트림을 사용하면 선언형 프로그래밍 방식으로 데이터를 처리할 수 있어 더욱 인간 친화적이고 직관적인 코드 작성이 가능합니다. 

 

지금까지는 어떤 주어진 과업을 달성하기 위해 코드 한 줄 한 줄의 동작 원리를 이해하고 순차적이고 세세하게 이를 규정하는 방식이였는데 이걸 명령형 프로그래밍이라고 합니다. "어떻게"코드를 작성할지에 대해 초점을 두고 있습니다.

 

  • 명령형 프로그래밍 방식(초점: 어떻게)
package Stream;

import java.util.List;

public class ImperativeProgramming {
    public static void main(String[] args) {
        //List에 있는 숫자 중에서 4보다 큰 짝수의 합계 구하기
        List<Integer> numbers = List.of(1,3,6,7,8,11);
        int sum = 0;

        for (int number : numbers){
            if(number>4 && (number % 2 == 0)){
                sum += number;
            }
        }

        System.out.println("명령형 프로그래밍을 사용한 합계 : " + sum);
    }
}

 

 

  • 선언형 프로그래밍 방식
package Stream;

import java.util.List;

public class DeclarativeProgramming {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1,3,6,7,8,11);

        int sum = numbers.stream()
                .filter(number -> number > 4 && (number % 2==0))
                .mapToInt(number ->number)
                .sum();

        System.out.println("선언형 프로그래밍을 사용한 합계 : " + sum);
    }
}

 

package Stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

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

        //ArrayList
        List<String> fruitList = new ArrayList<>();
        fruitList.add("바나나 ");
        fruitList.add("사과 ");
        fruitList.add("오렌지");

        //배열
        String[] fruitArray = {"바나나 ", "사과 ", "오렌지 "};

        //각각 스트림 생성
        Stream<String> ListStream = fruitList.stream();
        Stream<String> ArrayStream = Arrays.stream(fruitArray);

        //출력
        ListStream.forEach(System.out::println);
        ArrayStream.forEach(System.out::println);
    }
}

 

스트림의 특징

스트림의 4가지 특징들

1. 스트림 처리 과정은 생성, 중간 연산, 최종 연산 세 단계의 파이프라인으로 구성될 수 있다.

2. 스트림은 원본 데이터 소스를 변경하지 않는다.(read-only)

3. 스트림은 일회용이다.

4.스트림은 내부 반복자이다.