본문 바로가기
JAVA/이재환의 자바 프로그래밍 입문

[Java] Ch.23 스트림

by ♡˖GYURI˖♡ 2023. 10. 26.
728x90

스트림

  • 데이터의 흐름
  • 데이터가 여러 개가 있어야 흐름을 만들 수 있기 때문에 스트림 데이터 소스로는 컬렉션, 배열 등이 주로 사용딤
  • 스트림 데이터는 데이터 소스에서 추출한 연속적인 데이터
  • 스트림은 이런 연속적인 데이터의 흐름을 반복적으로 처리하는 기능

 

스트림의 특징

  • 스트림 연산은 기존 자료를 변경하지 않음
  • 스트림 연산은 중간 연산과 최종 연산으로 구분됨
  • 한 번 생성하고 사용한 스트림은 재사용 불가

 

스트림은 java.util.Stream 패키지의 멤버이며, BaseStream 인터페이스를 부모로 하여 4 종류의 스트림을 제공함

 

 

중간 연산, 최종 연산

중간 연산

  • filter() : 조건에 맞는 요소 추출
  • map() : 조건에 맞는 요소 변환
  • sorted() : 정렬

최종 연산

  • 스트림의 자료를 소모하면서 연산 수행
  • 최종 연산 후에 스트림은 더 이상 다른 연산을 적용할 수 없음
  • forEach() : 요소를 하나씩 꺼내옴
  • count() : 요소 개수
  • sum() : 요소의 합
import java.util.Arrays;
import java.util.stream.IntStream;

public class Ex01_Stream1
{
    public static void main(String[] args)
    {
        int[] arr = {1, 2, 3, 4, 5};

        // 스트림 생성        
        IntStream stm1 = Arrays.stream(arr);

        // 중간 연산
        IntStream stm2 = stm1.filter(n -> n%2 == 1);

        // 최종 연산
        int sum = stm2.sum();

        System.out.println(sum);
    }
}

 

 

파이프라인 구성

Stream 인터페이스가 제공하는 메서드는 대부분 반환 타입이 Stream이므로 메서드를 연속해 호출할 수 있음

따라서 스트림 연산을 연결해 파이프라인으로 구성할 수 있음

import java.util.Arrays;

public class Ex02_Pipeline
{
    public static void main(String[] args)
    {
        int[] arr = {1, 2, 3, 4, 5};

        // Pipeline 구성        
        int sum = Arrays.stream(arr)
                .filter(n -> n%2 == 1)
                .sum();

        System.out.println(sum);
    }
}

 

 

컬렉션 객체 vs 스트림

스트림을 사용하면 컬렉션만 사용한 것보다 코드가 간결하고, 쉽게 의미를 알 수 있음

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Ex03_CollectionVsStream
{
    public static void main(String[] args)
    {
        int[] arr = {1, 5, 3, 2, 4};
        List<Integer> list = new ArrayList<>();

        // 컬렉션 프레임워크를 이용한 방식
        for (int i : arr)
        {
            if (i%2 == 1)
            {
                list.add(i);
            }
        }

        Collections.sort(list);
        
        for (int i : list)
        {
            System.out.print(i + "\t");
        }

        System.out.println();
        
        // Stream 을 이용한 방식
        Arrays.stream(arr)
            .filter(n -> n%2 == 1)
            .sorted()
            .forEach(n -> System.out.print(n + "\t"));

        System.out.println();
    }
}

 

 

여러 가지 연산들

sorted()

스트림을 구성하는 데이터를 조건에 따라 정렬하는 연산

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

public class Ex04_Sorted
{
    public static void main(String[] args)
    {
        List<String> list = Arrays.asList("홍길동", "멀린", "해리포터");
        
        // 사전순 정렬
        list.stream()
            .sorted()
            .forEach(n -> System.out.print(n + "\t"));
        
        System.out.println();

        // 글자 길이순 정렬
        list.stream()
            .sorted((s1, s2) -> s1.length() - s2.length())
            .forEach(n -> System.out.print(n + "\t"));
    
        System.out.println();
    }
}

 

map()

스트림을 구성하는 데이터를 조건에 따라 변환하는 연산

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

public class Ex05_Map
{
    public static void main(String[] args)
    {
        List<String> list = Arrays.asList("apple", "banana", "orange");
        
        list.stream()
            .map(s -> s.toUpperCase())	// 대문자로 변환
            .forEach(n -> System.out.print(n + "\t"));
        
        System.out.println();
    }
}

 

sum(), count(), average(), min(), max()

import java.util.stream.IntStream;

public class Ex06_PreTerminal
{
    public static void main(String[] args)
    {
        // 합
        int sum = IntStream.of(1, 3, 5, 7, 9)
                           .sum();
        System.out.println("sum = " + sum);

        // 개수
        long cnt = IntStream.of(1, 3, 5, 7, 9)
                            .count();
        System.out.println("count = " + cnt);

        // 평균
        IntStream.of(1, 3, 5, 7, 9)
                 .average()
                 .ifPresent(avg -> System.out.println("avg = " + avg));

        // 최소
        IntStream.of(1, 3, 5, 7, 9)
                 .min()
                 .ifPresent(min -> System.out.println("min = " + min));

        // 최대
        IntStream.of(1, 3, 5, 7, 9)
                 .max()
                 .ifPresent(max -> System.out.println("max = " + max));
    }
}

 

reduce()

앞의 예제처럼 정의된 연산이 아닌 프로그래머가 직접 지정하는 연산을 적용함

Arrays.stream(arr).reduce(초깃값, (전달되는 요소) -> 기능);
Arrays.stream(arr).reduce(0, (a, b) -> a + b);

 

문자열 길이를 세서 긴 문자열을 남기는 예제

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

public class Ex07_Reduce
{
    public static void main(String[] args)
    {
        List<String> list1 = Arrays.asList("홍길동", "전우치", "손오공");

        String name1 = list1.stream()
                .reduce("이순신", (s1, s2) ->
                    s1.length() >= s2.length() ? s1 : s2);
        System.out.println(name1);

        List<String> list2 = Arrays.asList("홍길동", "멀린", "해리포터");

        String name2 = list2.stream()
                .reduce("이순신", (s1, s2) ->
                    s1.length() >= s2.length() ? s1 : s2);
        System.out.println(name2);
    }
}