프로그래밍/Java

Stream

hyokeunLee 2022. 5. 4. 22:31

Stream 이란? 


연속된 데이터를 처리하는 Operation(조작)의 모임. 

컬렉션 이나 배열 등에 저장되어 있는 요소들을 하나씩 참조하며 반복적인 처리를 가능케 하는 기능이다. 

Stream 을 이용한다면 불필요한 반복문이나 분기처리를 쓰지 않고도 직관적인 코드를 작성할 수 있다. 

 

 

 

Stream 특징 


  • 데이터를 담고 있는 저장소(컬렉션)이 아니다. 
  • Functional in nature, 즉 Stream 이 처리하는 데이터 소스를 변경하지 않는다. 
  • 무제한일 수도 있다. 
    • 실시간으로 계속해서 Stream 으로 들어온 데이터를 Stream 으로 받아 처리할 수 있다.
    • Short Circuit 메소드를 사용해서 제한하는 것도 가능하다.
  • 중개 오퍼레이션들은 근복적으로 Lazy 하다.
    • Stream API 는 크게 중계 오퍼레이션과 터미널 오퍼레이션, 두 가지로 나눌 수 있다.
    • 이 둘의 뜻은 계속 이어지는 오퍼레이션, 종료시키는 오퍼레이션을 뜻한다.
    • 이 둘의 가장 큰 차이는 Stream return 여부에 있다. 
  • 손쉽게 병렬처리 할 수 있다.

 

스트림 파이프 라인

  • 0 또는 다수의 중개 오퍼레이션 (intermediate operation)과 한개의 종료 오퍼레이션 (terminal operation) 으로 구성한다. 
  • Stream 의 데이터 소스는 오직 터미널 오퍼레이션을 실행할 때에만 처리한다. 
     
     

중개 오퍼레이션

  • Stream 을 리턴한다. 
  • Stateless / Stateful 오퍼레이션으로 더 상세하게 구분할 수도 있다. 
    (대부분은 Stateless 지만, distinct 나 sorted 처럼 이전 소스 데이터를 참조해야하는 오퍼레이션은 Stateful 오퍼레이션이다.) 
  • fillter, map, skip, sorted, ...

 

 

종료 오퍼레이션

  • Stream 을 리턴하지 않는다.
  • collect, allMatch, count, forEach, min, max, ...
 

 

 

parallelStream( ) 

 

  • 일반 for 문과 if 문으로 구성된 코드를 stream 혹은 parallelStream 으로 변경해보자.
public class Main {
  public static void main(String[] args) {
    List<String> names = new ArrayList<>();
    names.add("hyokeun");
    names.add("and");
    names.add("jungkeung");
    
    // 적용 전
    for (String name: names) {
      if (name.startsWith("h")) {
        System.out.println(name.toUpperCase());
      }
    }

    // 적용 후
    names.parallelStream().filter(s -> s.startsWith("h")).map(String::toUpperCase)
        .collect(Collectors.toList()).forEach(System.out::println);
  }
}
  • parallelStream 은 멀티 쓰레드를 사용하여 데이터를 처리하는 함수인데, 무조건 좋은것은 아니다.
  • 쓰레드를 생성하고 자원 수집, 컨텍스트 스위칭 비용 등을 고려한 후 데이터가 방대하게 큰 경우에 stream 과 직접 성능 비교 한 후 사용하는것이 올바르다 .

 

 

 

 

Stream 실습 


package com.study.java8to11;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamStudy {
  public static void main(String[] args) {
    List<OnlineClass> springClasses = new ArrayList<>();
    springClasses.add(new OnlineClass(1, "spring boot",true));
    springClasses.add(new OnlineClass(2, "spring data jpa",true));
    springClasses.add(new OnlineClass(3, "spring mvc",false));
    springClasses.add(new OnlineClass(4, "spring core",false));
    springClasses.add(new OnlineClass(5, "rest api dev",false));

    System.out.println("spring 으로 시작하는 수업");
    springClasses.stream()
        .filter(s -> s.getTitle().startsWith("spring"))
        .forEach(s -> System.out.println(s.getId()));

    System.out.println("close 되지 않은 수업");
    springClasses.stream()
            .filter(Predicate.not(OnlineClass::isClosed))
            .forEach(s -> System.out.println(s.getId()));

    System.out.println("수업 이름만 모아서 스트림 만들기");
    springClasses.stream()
        .map(OnlineClass::getTitle)
        .forEach(System.out::println);

    List<OnlineClass> javaClasses = new ArrayList<>();
    javaClasses.add(new OnlineClass(6, "The Java, Test",true));
    javaClasses.add(new OnlineClass(7, "The Java, Code manipulation",true));
    javaClasses.add(new OnlineClass(8, "The Java, 8 to 11",false));

    List<List<OnlineClass>> hyokeunEvents = new ArrayList<>();
    hyokeunEvents.add(springClasses);
    hyokeunEvents.add(javaClasses);

    System.out.println("두 수업 목록에 들어있는 모든 수업 아이디 출력");
    hyokeunEvents.stream()
            .flatMap(Collection::stream)
            .forEach(s -> System.out.println(s.getId()));

    System.out.println("10부터 1씩 증가하는 무제한 스트림 중에서 앞에 10개 빼고 최대 10개 까지만");
    Stream.iterate(10 ,i -> i + 1)
            .skip(10)
            .limit(10)
            .forEach(System.out::println);

    System.out.println("자바 수업 중에 Test가 들어있는 수업이 있는지 확인");
    boolean test = javaClasses.stream().anyMatch(oc -> oc.getTitle().contains("Test"));
    System.out.println(test);

    System.out.println("스프링 수업 중에 제목에 spring 이 들어간 제목만 모목서 List로 만들기");
    springClasses.stream()
        .map(OnlineClass::getTitle)
        .filter(t -> t.contains("spring"))
        .collect(Collectors.toList())
        .forEach(System.out::println);

  }
}

 

 

 

참고 


 

'프로그래밍 > Java' 카테고리의 다른 글

Date와 Time API  (0) 2022.05.05
Optional  (0) 2022.05.05
Lombok 동작원리  (0) 2022.05.03
다이나믹 프록시  (0) 2022.05.03
클래스 로더 (class loader)  (0) 2022.05.01