[Java] 스트림

박채은·2022년 11월 14일
0

Java

목록 보기
24/30

스트림이란?

  • 다양한 데이터 소스(컬렉션, 배열)를 표준화해서 다루는 방법
  • 배열, 컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자

특징

  • 읽기만 가능
    • 원본을 변경하지 않음(read-only)
  • 일회용 (one-time only)
    • 최종 연산이 끝나고, 다시 데이터 처리를 하기 위해서는 스트림을 재생성해야 한다.
  • 람다식을 사용
  • 중간 연산과 최종 연산을 수행할 수 있다.
    • 중간 연산자는 여러 번 사용이 가능한 반면, 최종 연산자는 딱 한번만 사용 가능하며 스트림은 닫힌다.
  • 선언형 프로그래밍 방식( ↔ 명령형)을 사용한다.
    • "어떻게" 보다 "무엇을" 수행하는지에 집중하는 프로그래밍 패러다임
    • 내부적으로는 어떻게 동작하는지 정확히 알지 못하나, 선언을 통해 코드가 무엇을 수행하는지 알 수 있다.
      ex) filter : 내부 구조는 모르겠는데, filtering 된다는 것은 알겠음
  • 병렬 스트림 사용 가능

단계

  1. 스트림 생성
  2. 중간 연산(여러 번 가능) - 매핑, 필터링, 정렬
  3. 최종 연산(한 번만) - 반복, 카운팅, 평균, 총합 등의 집계

파이프라인

한 데이터 처리 단계의 출력이 다음 단계의 입력으로 이어지는 형태의 연결된 구조

파이프라인은 여러 개의 스트림으로 연결되어져 있다.


스트림 메서드

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

스트림 생성

[ Collection의 stream 생성 ]

  • Collection 인터페이스에는 stream()이 정의되어 있다.
// String
List<String> list = Arrays.asList("a", "b");
Stream<String> streamList = list.stream();

// Integer
List<Integer> list = Arrays.asList(1,2,3);
Stream<Integer> streamList = list.stream(); // Stream<Integer>

[ 배열의 stream 생성 ]

  • Stream<T> 에서 T에는 객체만 입력될 수 있다.
// String
Stream<String> stream = Stream.of("a", "b", "c");
Stream<String> stream = Arrays.stream(new String[] {"a", "b", "c"});

// int
int[] arr = {1,2,3};
IntStream stream = Arrays.stream(arr); // IntStream
// Stream<Integer> stream = Stream.of(arr); // 불가능

[ 원시 자료형의 stream 생성 ]

  • 원시 자료형(int, double, long)들을 위한 stream이 따로 존재한다.
IntStream stream = IntStream.range(4,10);

중간 연산

  • Stream<T> distinct() : 중복 제거
  • Stream<T> filter() : 조건에 맞는 데이터만 필터링
  • map(Function mapper) : 기존의 stream의 원소를 맵핑한 다음, 새로운 stream으로 형성
  • IntStream mapToInt(Function mapper) : mapper를 적용한 IntStream을 리턴
  • Stream<T> sorted() : 인자가 없으면, 오름차순 정렬
  • Stream<T> peek() : 중간에 결과를 디버깅할 때 사용

map, peek, forEach의 차이점

  • map: 중간 연산 (매핑)
  • peek: 중간 연산 (반복 + 출력)
  • forEach: 최종 연산 (반복 + 출력)

map과 flatMap의 차이점

map()은 원소에 mapper를 적용하여, 그대로 스트림으로 반환하지만,
flatMap()은 중첩 구조를 한 단계 제거한 스트림으로 반환한다. (2차원 배열 -> 1차원 배열)

public class Main {
    public static void main(String[] args) {
        Stream<String[]> stringArraysStream = Stream.of(
                new String[]{"hello", "world", "java"},
                new String[]{"chae", "eun"});

        stringArraysStream.flatMap(Arrays::stream) // Stream<String>
                .peek(System.out::println) // hello, world, java, chae, eun
                .map(e-> e.split("")) // Stream<String[]> // hello -> [h, e, l, l, o]
                .forEach(e-> System.out.println(Arrays.toString(e))); 

    }
}

// 출력
hello
[h, e, l, l, o]
world
[w, o, r, l, d]
java
[j, a, v, a]
chae
[c, h, a, e]
eun
[e, u, n]

[참고]
https://stackoverflow.com/questions/26684562/whats-the-difference-between-map-and-flatmap-methods-in-java-8
https://kchanguk.tistory.com/56
https://devjem.tistory.com/41
https://mangkyu.tistory.com/115


IntStream

숫자와 관련된 메소드들이 존재한다.
ex) sum()

  • mapToInt() : 스트림을 IntStream으로 변환
int sum = numbers.stream() // 스트림 생성
                 .filter(number -> number > 4 && (number % 2 == 0)) // 필터링
                 .mapToInt(number -> number) // IntStream으로 매핑
                 .sum(); // 총합

최종 연산

  • sum(), count(), average(), max(), min()
  • reduce()
  • collect() : Stream의 요소들을 List, Set, Map 등으로 collect

(더 자세한 내용은 추가로 기입해두기)

0개의 댓글