ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Stream
    프로그래밍/Java 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
Designed by Tistory.