Notice
Recent Posts
Recent Comments
Link
관리 메뉴

look-forest

Stream 본문

Java/모던 자바(Java 8+)

Stream

studyHub 2024. 11. 9. 17:56

Stream 소개

Stream

  • sequence of elements supporting sequential and parallel aggregate operations
    순차적 및 병렬 집계 연산을 지원하는 요소들의 시퀀스(데이터 요소들이 특정 순서로 배열된 컬렉션)
  • 데이터를 담고 있는 저장소 (컬렉션)이 아니다.
  • Funtional in nature, 스트림이 처리하는 데이터 소스를 변경하지 않는다.
  • 스트림으로 처리하는 데이터는
    - 오직 한번만 처리한다.
    - 무제한일 수도 있다. (Short Circuit 메소드를 사용해서 제한할 수 있다.)

 

스트림 파이프라인

  • 컨베이어 벨트처럼, 스트림 시퀀스를 처리하는 operation의 모음.
  • 0 또는 다수의 중개 오퍼레이션과 한개의 종료 오퍼레이션으로 구성
  • 스트림의 데이터 소스는 오직 터미널 오퍼네이션을 실행할 때에만 처리한다.
    =>
    중개 오퍼레이션은 근본적으로 lazy 하다

중개 오퍼레이션 (intermediate operation)

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

 

종료 오퍼레이션  (terminal operation)

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

 

스트림 병렬 처리

  • parallelStream()을 사용하면 알아서 병렬 처리를 해준다. (feat. spliterator)
  • 병렬 처리가 항상 빠른 것은 아니다.
    스레드 생성, 스위칭 비용, 시퀀스 분리/병합 비용 등 발생하므로.. 대용량 처리할 경우에 유용.
//직렬 처리
names.stream().map(s -> {
    System.out.println(s + " => " + Thread.currentThread().getName());
    return s.toUpperCase();
}).toList();

System.out.println("===================================================================");

//병렬 처리
names.parallelStream().map(s -> {
    System.out.println(s + " => " + Thread.currentThread().getName());
    return s.toUpperCase();
}).toList();
결과

 

 


Stream API

걸러내기

  • Filter(Predicate)
  • 예) 이름이 3글자 이상인 데이터만 새로운 스트림으로

 

변경하기

  • Map(Function) 또는 FlatMap(Function)
  • 예) 각각의 Post 인스턴스에서 String title만 새로운 스트림으로
  • 예) List<Stream<String>>을 String의 스트림으로
List<List<OnlineClass>> classList = new ArrayList<>();

//flatting : 스트림 인자가 List일 때, List에 있는 내용들을 다 꺼내서 스트림으로 만든다.
System.out.println("# 두 수업 목록에 들어있는 모든 수업 아이디 출력");
classList.stream()
        // .flatMap(list -> list.stream())
        .flatMap(List::stream) // => Stream<OnlineClass> 반환
        .forEach(oc -> System.out.println(oc.getId()));

 

생성하기

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

 

제한하기

  • limit(long) 또는 skip(long)
  • 예) 최대 5개의 요소가 담긴 스트림을 리턴한다.
  • 예) 앞에서 3개를 뺀 나머지 스트림을 리턴한다.
System.out.println("# 10부터 1씩 증가하는 무제한 스트림 중에서 앞에 10개 빼고 최대 10개 까지만");
Stream.iterate(10, i -> i + 1) //무제한 스트림 생성. but 중계형 오퍼레이터라 실행x
        .skip(10)
        .limit(10)
        .forEach(System.out::println);

 

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

  • anyMatch(), allMatch(), nonMatch()
  • 예) k로 시작하는 문자열이 있는지 확인한다. (true 또는 false를 리턴한다.)
  • 예) 스트림에 있는 모든 값이 10보다 작은지 확인한다.
System.out.println("# 자바 수업 중에 Test가 들어있는 수업이 있는지 확인");
boolean result = javaClasses.stream()
        .anyMatch(oc -> oc.getTitle().contains("Test"));  //allMatch는 모두 true여야 true

 

개수 세기

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

 

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

  • collect(), reduce(identity, BiFunction), sum(), max()
  • 예) 모든 데이터를 하나의 List 또는 Set에 옮겨 담기
  • 예) 모든 숫자 합 구하기
System.out.println("# 스프링 수업 중에 제목에 spring이 들어간 제목만 모아서 List로 만들기");
List<String> collect = springClasses.stream()
        .filter(oc -> oc.getTitle().contains("spring"))
        .map(OnlineClass::getTitle)
        //.collect(Collectors.toSet())
        .toList();
System.out.println("# 초기값 0에서 시작해 각 요소를 순차적으로 더해 총합을 계산");
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
//reduce : 초기값과 집계 함수(accumulator)를 받아 각 요소를 순차적으로 처리하여 결과를 계산
int sum = numbers.stream()
        .reduce(0, (a, b) -> a + b);

System.out.println("리스트의 합: " + sum);  // 출력: 리스트의 합: 15

 

 

 

 


참고 자료 & 이미지 출처
더 자바, Java 8 (백기선 님)

 

'Java > 모던 자바(Java 8+)' 카테고리의 다른 글

CompletableFuture  (0) 2024.11.09
Date와 Time  (0) 2024.11.09
Optional  (0) 2024.11.09
인터페이스의 변화  (0) 2024.11.08
함수형 인터페이스와 람다  (2) 2024.11.07