모르지 않다는 것은 아는것과 다르다.

Java

Stream

채마스 2022. 2. 26. 00:15

Stream 이란?

  • sequence of elements supporting sequential and parallel aggregate operations
  • 스트림이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 의미한다.
  • 스트림으로 처리하는 데이터는 오직 한번만 처리된다.
  • 무제한일 수도 있다. (Short Circuit 메소드를 사용해서 제한할 수 있다.) -> 예를들어 앞에 10개만 검사할 수 있다.
  • 중개 오퍼레이션은 근본적으로 lazy 하다.
  • 손쉽게 병렬 처리할 수 있다.
    • ex>
    List<String> collect = names.parallelStream().map(String::toUpperCase).collect(Collectors.toList());
    collect.forEach(System.out.println);
    • 위와 같이 병렬 처리된 결과값을 List로 반환해준다.

 

스트림 파이프라인

  • 0 또는 다수의 중개 오퍼레이션 (intermediate operation)과 한개의 종료 오퍼레이션 (terminal operation)으로 구성한다.
  • 스트림의 데이터 소스는 오직 터미널 오퍼네이션을 실행할 때에만 처리한다.
  • 종료 오퍼레이션이 있기 전까지 실행하지 않는다.
  numbers.stream().map((s) -> {
      System.out.println(s);
      return s.toUpperCase();
  })
  • 위에서 System.out.println(s); 가 실행되지 않는다. -> 종료 오퍼레이션이 없기 때문이다.

 

중개 오퍼레이션

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

 

종료 오퍼레이션

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

 

Stream API

 

걸러내기

  • Filter(Predicate)
  • ex>
  // spring 으로 시작하는 수업
  springClasses .stream()
              .filter(oc -> oc.getTitle().startsWith("spring"))
              .forEach(oc -> System.out.println(oc.getId()));

  // close 되지 않은 수업
  springClasses.stream()
              .filter(oc -> !oc.isClosed()) // .filter(Predicate.not(OnlineClass::isClosed)) 로 대체할 수 있다.
              .forEach(oc -> System.out.println(oc.getId()));

 

변경하기

  • Map(Function) 또는 FlatMap(Function)
  • 예) 각각의 Post 인스턴스에서 String title만 새로운 스트림으로
  • 예) List을 String의 스트림으로
  • ex>
  // 수업 이름만 모아서 스트림 만들기
  springClasses.stream()
              .map(ec -> oc.getTitle()) // String 타입으로 변경
              .forEach(oc -> System.out.println(oc.getId()));
  List<List<OnlineClass>> lists = new ArrayList<>();
      lists.add(springClasses);
      lists.add(javaClasses);

  // 두 수업 목록에 들어있는 모든 수업 아이디 출력
  lists.stream()
          .flatMap(list -> list.stream())
          .forEach(oc -> System.out.println(oc.getId()));

 

생성하기

  • generate(Supplier) 또는 Iterate(T seed, UnaryOperator)
  • 예) 10부터 1씩 증가하는 무제한 숫자 스트림
  • 예) 랜덤 int 무제한 스트림

 

제한하기

  • limit(long) 또는 skip(long)
  • 예) 최대 10개의 요소가 담긴 스트림을 리턴한다.
  • 예) 앞에서 10개를 뺀 나머지 스트림을 리턴한다.
  • ex>
  Stream.iterate(10, i -> i + 1)
      .skip(10)
      .limit(10)
      .forEach(System.out::println);

 

스트림에 있는 데이터가 특정 조건을 만족하는지 확인

  • anyMatch(), allMatch(), nonMatch()
  • 예) k로 시작하는 문자열이 있는지 확인한다. (true 또는 false를 리턴한다.)
  • 예) 스트림에 있는 모든 값이 10보다 작은지 확인한다.
  • ex>
  javaClasses.stream()
      .anyMatch(oc -> oc.getTitle().contains("Test"));

 

개수 세기

  • count()
  • 예) 10보다 큰 수의 개수를 센다.

 

스트림을 데이터 하나로 뭉치기

  • reduce(identity, BiFunction), collect(), sum(), max()
  • 예) 모든 숫자 합 구하기
  • 예) 모든 데이터를 하나의 List 또는 Set에 옮겨 담기

 

정렬하기

  • sorted 를 이용해서 쉽게 정렬을 할 수 있다.
.stream().sorted(
                Comparator
                        .comparing(User::getUserAge)
                        .thenComparing(User::getUsername)
                        .thenComparing(User::getuserId)
).collect(Collectors.toList());

 

flatMap

  • 만약 Order 라는 클래스가 있고 Order 는 List 를 갖는다고 했을 때 아래와 같이 flatMap 을 사용할 수 있다.
List<OrderLine> mergedOrderLines = orders.stream()     // Stream<Order>
                .map(Order::getOrderLines)                    // Stream<List<OrderLine>>
//                .map(List::stream)                          // Stream<Stream<OrderLin>>
                .flatMap(List::stream)                         // Stream<OrderLine>
                .collect(Collectors.toList());

 

 

REFERENCES

  • 백기선님의 더 자바, Java 8

'Java' 카테고리의 다른 글

Thread  (0) 2022.02.26
String,StringBuilder,StringBuffer  (0) 2022.02.26
Static 변수와 Static 메서드  (0) 2022.02.26
Optional  (0) 2022.02.26
Object 클래스  (0) 2022.02.26