BACKEND/JAVA

자바 - 스트림(Stream)

우진하다 2023. 6. 4. 14:33

스트림(Stream).

자료가 모여 있는 배열 또는 컬렉션, 일련의 연산이나 정렬, 숫자를 처리하는 기능 등이
미리 구현되어 사용할 수 있다면 간결하고 일관성있는 코드 작성이 가능합니다.

여러 자료의 처리에 대한 기능을 구현해 놓은 클래스가 바로 스트림 입니다.
스트림을 활용하면 배열, 컬렉션 등의 자료를 일관성 있게 처리할 수 있습니다.
(입출력 스트림과는 다른 개념입니다.)

예로 1부터 5까지 정수를 담은 배열과 ArrayList의 요소를 하나씩 출력한다고 가정한다면 아래와 같이 작성할 수 있습니다.

package june2023.day04;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.IntStream;

public class StreamAPITest {
    public static void main(String[] args) {
        int[] intArr = {1, 2, 3, 4, 5};
        ArrayList<Integer> list = new ArrayList<>(Arrays.asList(10, 20, 30, 40, 50));
        // 반복문을 사용해 각 요소 출력
        for (int i = 0; i < intArr.length; i++) {
            System.out.printf("%d ", intArr[i]);
        }
        System.out.println();

        for (int i = 0; i < list.size(); i++) {
            System.out.printf("%d ", list.get(i));
        }
        System.out.println();

        // 배열 스트림 생성하여 출력
        Arrays.stream(intArr).forEach(n -> System.out.printf("%d ", n));
        System.out.println();

        // 컬렉션 스트림 생성하여 출력
        list.stream().forEach(n -> System.out.printf("%d ", n));
        System.out.println();
        
        // 인트스트림 생성하여 출력
        IntStream.rangeClosed(1, 5).forEach(n -> System.out.printf("%d ", n));
    }
}
Arrays.stream(intArr).forEach(n -> System.out.printf("%d ", n));
|<-- 스트림 생성 부분 -->.<---- 출력하는 부분 / (중개연산 + 최종연산) ---->

스트림을 생성하고 미리 구현되어 있는 forEach() 메서드를 사용해 배열의 요소를 하나씩 거내어 출력합니다.
반복문을 작성하는 것보다 간단하게 작성하고 원하는 결과를 얻을 수 있습니다.
스트림 구성은 Stream 생성, 중개연산, 최종연산으로 구성됩니다.

 

스트림의 연산.

스트림의 연산에는 크게 중간연산과 최종연산으로 구분합니다.
중간 연산은 자료를 거르거나 변경하여 또 다른 자료를 내부적으로 생성합니다.
최종 연산은 생성된 내부 자료를 소모해 가면서 연산을 수행합니다.
따라서 최종 연산은 마지막에 한 번만 호출되며
최종 연산이 호출되어야 중간 연산의 결과가 만들어 집니다.
자주 사용하는 연산을 알아봅시다.

중간 연산 - filter / map

filter()는 조건을 넣고 그 조건에 맞는 참인 경우만 추출하는 경우에 사용
case1. 문자열 배열이 있을 때 문자열 길이가 3이상인 경우에 출력하는 경우

String[] strings = {"Apple", "is", "Jobs"};
Arrays.stream(strings).filter(s -> s.length() >= 3).forEach(s -> System.out.printf("%s ", s));
// 스트림 생성           // 중간연산                    // 최종연산
// Apple Jobs

map()은 함수를 적용하여 각 요소를 변환하는 중간 연산입니다.
map()을 사용하면 스트림의 각 요소를 지정된 함수에 적용하여 새로운 요소로 매핑할 수 있습니다.
주로 데이터 변환 작업에 활용되며, 기존 요소를 다른 형태로 변환하거나, 
특정 필드를 추출하여 새로운 형태로 매핑하는 등의 작업에 유용합니다.
case1. 기존 문자열에 "s" 추가하여 출력하기

String[] strings = {"Apple", "is", "Jobs"};
Arrays.stream(strings).map(s -> s + "s").forEach(s -> System.out.printf("%s ", s));
// Apples iss Jobss

case2. 기존 정수 List에 제곱한 값을 새로운 List로 만들기

ArrayList<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
ArrayList<Integer> squareNumbers = numbers.stream()
                                .map(n -> n * n)
                                .collect(Collectors.toCollection(ArrayList::new));
                                
System.out.println(squareNumbers); // [1, 4, 9, 16, 25]

 

최종 연산 

최종 연산은 스트림의 자료를 소모하면서 연산을 수행하기 때문에 최종 연산이 수행되고 나면 해당 스트림은 더 이상 사용할 수 없습니다.
최종 연산은 결과를 만드는 데 주로 사용합니다.

        // Sum, Average
        int sum = IntStream.range(1, 5).sum(); // 1 ~ 4
        System.out.println(sum); // 10

        double average = IntStream.range(1, 5).average().getAsDouble();
        System.out.println(average); // 2.5

        // Min, Max
        int min = IntStream.range(1, 5).min().getAsInt();
        System.out.println(min); // 1
        int max = IntStream.rangeClosed(1, 5).max().getAsInt();
        System.out.println(max); // 5

        // reduce
        Stream<Integer> stream = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5)).stream();
        System.out.println(stream.reduce((x, y) -> x + y).get()); // 15, 연쇄적으로 합함

        // reduce strings = {"Apple", "is", "Jobs"};
        Stream<String> stringStream = Arrays.stream(strings);
        System.out.println(stringStream.reduce("init : ", (s1, s2) -> s1 + s2));
        // init : AppleisJobs

        // forEach
        IntStream.rangeClosed(1, 10)
                .filter(x -> x % 2 == 0)
                .forEach(x -> System.out.print(x + " ")); // 2 4 6 8 10

 

스트림의 특징.

자료의 대상과 관계없이 동일한 연산을 수행한다.
한 번 생성하고 사용한 스트림은 재사용 할 수 없다.
스트림의 연산은 기존 자료를 변경하지 않는다.
스트림의 연산은 중간 연산과 최종 연산이 있다.

'BACKEND > JAVA' 카테고리의 다른 글

클래스의 속성과 기능  (0) 2023.06.05
객체지향 프로그래밍과 클래스  (0) 2023.06.05
자바 클래스 - Wrapper 클래스  (0) 2023.06.03
자바 클래스 - String 클래스  (0) 2023.05.27
자바 클래스 - Object 클래스  (0) 2023.05.27