사이먼's 코딩노트

[Java] Stream 본문

Java/Java

[Java] Stream

simonpark817 2024. 5. 2. 22:43

[스트림(Stream)]

  • 자바 스트림이란 Java 8부터 추가된 기술로 람다를 활용하여 배열과 컬렉션을 함수형으로 간단하게 처리할 수 있는 기술이다.
  • Stream 이라는 단어의 뜻대로 데이터의 흐름을 의미한다.
  • 기존의 for문이나 배열을 사용하면 코드가 길어져서 가독성과 재사용성이 떨이지며, 데이터 타입마다 다른 방식으로 다뤄야하는 불편함이 있다.
  • 하지만, 스트림은 데이터 소스를 추상화하고, 데이터를 다루는 데에 자주 사용되는 메서드를 정의해 놓아서 데이터 소스에 상관없이 모두 같은 방식으로 다룰 수 있으므로 코드의 재사용성이 높아진다.
  • 스트림을 사용하면 파일에 저장된 데이터도 모두 같은 방식으로 다룰 수 있다.
  • 스트림은 일회용이라는 특징을 가지고있다.

 

[반복문]

  • 아래 코드는 일반 for문 버전의 반복문과, Stream을 사용한 반복문을 작성한 코드이다.
package org.example;

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        // 일반 버전
        for(int i = 1; i <= 10; i++) {
            System.out.println(i);
        }

        // 스트림 버전
        IntStream.range(1, 11)
                .forEach(e -> {
                    System.out.println(e);
                });

        IntStream.rangeClosed(1, 10)
                .forEach(e -> { System.out.println(e); });

        IntStream.rangeClosed(1, 10)
                .forEach(System.out::println);
    }
}
  • 보통 for문을 사용할 때는 i의 시작과 끝의 값, 보폭을 선언하고 for문 안에 반복하고자 하는 코드를 작성한다.
  • Stream을 이용하여 반복문을 작성할 때는 위의 예시와 같이 3가지 버전으로 코드를 작성할 수 있다.
  • 3가지 버전은 모두 같은 결과를 보여주지만, 아래로 내려갈수록 코드가 간소화된 모습을 볼 수 있다.
  • 먼저 시작과 끝의 값을 지정해주기 위해서 IntStream.range 또는 rangeClosed를 사용하는데 range 뒤에 오는 인자와 rangeClosed 뒤에 오는 인자의 값에는 차이가 있다.
  • 인자에는 범위가 오게 되는데 range(1, 11)은 1부터 10까지 끝 값인 11를 포함하지 않고, rangeClosed(1, 10)도 1부터 10까지 끝 값인 10을 포함한다.
  • forEach()를 통해 for문과 같은 역할을 수항하고, 매개변수에 대입된 람다식을 데이터 소스의 모든 요소에 적용한다.

 

[배열]

  • 다음은 일반 배열을 선언하여 각 배열의 자리에 있는 숫자에 2를 곱한 결과와 Stream을 사용하여 각 배열의 자리에 있는 숫자에 2를 곱한 결과를 작성한 코드이다.
package org.example;

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        // 일반 배열
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        for(int i = 0; i < arr.length; i++) {
            arr[i] *= 2;
        }

        System.out.println(Arrays.toString(arr));

        // 스트림 배열
        arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        int[] resultArr = Arrays.stream(arr)
                .map(e -> {
                    return e * 2;
                })
                .toArray();

        resultArr = Arrays.stream(arr)
                .map(e -> e * 2)
                .toArray();

        System.out.println(Arrays.toString(resultArr));
    }
}
  • 보통 배열에 값을 저장하기 위해서는 { } 안의 값을 작성하고, 해당 값에 연산을 원하면 for문을 사용하여 arr[i]에 차례로 접근하여 연산을 진행한다.
  • Stream을 이용하여 배열 안의 값을 연산하고 싶다면 위의 예시와 같이 2가지 버전으로 코드를 작성할 수 있다.
  • 2가지 버전은 모두 같은 결과를 보여주지만, 아래로 내려갈수록 코드가 간소화된 모습을 볼 수 있다.
  • Arrays.stream()을 통해 최초에 선언된 배열을 선택하고 .map()을 통해 원하는 연산을 진행하고 마지막에 .toArray()를 통해 다시 배열로 정렬한다.
  • 출력문에서 단순히 resultArr를 출력한다면 해당 배열의 주소값이 나오기 때문에 배열 안에 위치한 값을 보기 위해선 Arrays.toString()을 반드시 작성해야한다.

 

[리스트]

  • 다음은 일반 배열을 선언하여 각 배열의 자리에 있는 숫자가 홀수인지 짝수인지 먼저 필터링하여 리스트에 담아두고, 리스트에 있는 필터링된 값들에 2를 곱한 결과와 Stream을 사용하여 같은 방법을 적용한 코드이다.
package org.example;

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

public class Main {
    public static void main(String[] args) {
        // 일반 리스트 필터링
        int[] arr = {12, 57, 64, 43, 55, 76, 24, 97, 82, 72};

        // filter 시작
        List<Integer> resultAl = new ArrayList<>();

        for(int n : arr) if(n % 2 == 0) resultAl.add(n);
        // filter 끝

        // map 시작
        for(int i = 0; i < resultAl.size(); i++) {
            int newValue = resultAl.get(i) * 2;
            resultAl.set(i, newValue);
        }
        // map 끝

        System.out.println(resultAl);


        // 스트림 리스트 필터링
        arr = new int[]{12, 57, 64, 43, 55, 76, 24, 97, 82, 72};

        resultAl = Arrays.stream(arr)
                .filter(e -> e % 2 == 0)
                .map(e -> e * 2)
                .boxed()
                .collect(Collectors.toList());

        System.out.println(resultAl);
    }
}
  • arr에 담긴 값들을 필터링하기 위해 생성한 resultAl 리스트가 있다.
  • 향상된 for문을 사용하여 짝수인 값들은 모두 add()를 통해 resultAl에 담아 필터링을 끝낸다.
  • 그 다음, 필터링된 resultAl의 크기만큼 반복하면서 newValue 변수에 각 필터링된 숫자에 2를 곱하여 set()를 통해 다시 2를 곱한 newValue 값을 저장한다.
  • Stream을 이용하여 위와 같은 방법을 동일하게 적용할 수 있다.
  • Arrays.stream()을 통해 최초에 선언된 배열을 선택하고 .filter()를 통해 짝수를 필터링해준다.
  • .map()을 통해 원하는 연산을 진행하고 .collect(Collectors.toList())를 통해 스트림의 모든 요소를 배열로 변환한다.
  • 이 때, IntStream 같이 원시 타입에 대한 스트림 지원을 클래스 타입으로 전환하여 전용으로 실행 가능한 기능을 수행하기 위해서 .boxed()를 추가 작성한다.

 

반응형

'Java > Java' 카테고리의 다른 글

[Java] 예외처리 / 접근제한자  (0) 2024.03.19
[Java] 인터페이스  (2) 2024.03.19
[Java] 제네릭 / HashMap / 정리  (0) 2024.03.18
[Java] ArrayList  (2) 2024.03.18
[Java] 배열 / toString / equals / StringBuilder  (2) 2024.03.14