05. 스트림 활용

5.1 필터링#

  • Predicate 필터링
    • boolean 반환 함수로 .filter() 적용
  • 고유 요소 필터링
    • .distinct() 로 적용
    • 고유여부는 hashCode, equals 로 결정

5.2 스트림 슬라이싱 (java 9)#

  • 스트림의 요소를 선택하거나 스킵하는 다양한 방법 설명

Predicate 이용한 Slicing#

  • .takeWhile(Predicate)
    • filter 계열
    • 순환 중 조건에 만족하지 못하면 그 이후 객체는 순환하지 않음
  • .dropWhile(Predicate)
    • filter 계열
    • takeWhile가 반대, 거짓이 되는 지점까지 발견된 요소를 버림

스트림 축소#

  • .limit(long)
    • 중간 연산
    • 입력한 수 만큼 요소 개수 제한

요소 건너뛰기#

  • .skip(long)
    • 중간 연산
    • 입력한 수 만큼 요소를 생략

5.3 매핑#

스트림 각 요소에 함수 적용#

  • .map(Function)
    • 중간 연산
    • 인수로 입력된 Function을 이용해 각 요소를 변환

스트림 평면화#

  • .flatMap(Function<?, ? extends Stream>)
    • 중간 연산
    • 인수로 스트림 Function을 받음
    • 해당 스트림으로 한 차원 평면화 함

5.4 검색과 매칭#

  • 특정 속성이 데이터 집합에 있는 지 여부 검색

쇼트 서킷#

  • 전체 스트림을 처리하지 않더라도 결과를 반환할 수 있는 방식
  • || 연산이나 && 연산 생각하면 선행 조건에 의해 후의 조건을 판별 안해도 됨을 알 수 있음

적어도 한 요소#

  • boolean anyMatch(Predicate)
    • 쇼트 서킷 최종 연산
    • 하나라도 만족하면 true 반환

모든 요소와 일치#

  • boolean allMatch(Predicate)
    • 쇼트 서킷 최종 연산
    • 모든 요소가 만족하면 true 반환
  • boolean noneMatch(Predicate)
    • 쇼트 서킷 최종 연산
    • 모든 요소가 불만족하면 true 반환

요소 검색#

  • Optional<T> findAny()
    • 쇼트 서킷 최종 연산
    • 병렬적으로 실행되었을 때 랜덤으로 찾음
  • Optional<T> findFirst()
    • 쇼트 서킷 최종 연산
    • 병렬적으로 실행되도 기존 순서의 첫번째를 찾을 수 있도록 보장

5.5 리듀싱#

  • Optional<T> redice(BinaryOperator<T>)
  • T reduce(T, BinaryOperator<T>)
    • 최종 연산
    • 모든 스트림 요소를 처리해서 값으로 추출
    • 함수형에선 fold 라고 부르기도 함
    • 내부구현을 이용함으로 병렬성 전환에 대한 이점을 얻을 수 있음

내부 상태를 갖는 연산#

  • stateful operation
  • 결과를 위해 내부 버퍼가 필요한 연산
    • reduce, sum, max 는 내부 상태의 크기가 한정(bounded)되어 있음
    • sorted나 distinct 같은 연산은 모든 요소가 버퍼에 추가되어 있어야 함 (비한정)

5.7 숫자형 스트림#

기본형 특화 스트림#

  • 스트림 API의 박싱 비용을 피하도록 IntStream, LongStream, DoubleStream 을 제공
  • 일반 스트림을 변환할 시엔 .mapToInt 와 같은 형태의 중간 연산을 이용
  • .boxed 로 특화 스트림을 다시 일반 스트림으로 바꿀 수 있음
  • IntStream, LongStream 에서 숫자 범위 스트림을 생성하는 기능을 가지고 있음
    • IntStream.rangeClosed(1, 100): 1 <= n <= 100 의 범위를 나타내는 스트림
    • IntStream.range(1, 100): 1 < n < 100 의 범위

5.8 스트림 만들기#

  • 값으로 스트림 만들기
    • Stream<String> stream = Stream.of("Modern", "Java", "In", "Action));
  • 빈 스트림
    • Stream<String> stream = Stream.empty()
  • null이 될 수 있는 객체로 스트림 만들기
// null 처리 코드
String homeValue = System.getProperty("home");
Stream<String> homeValueStream =
homeValue == null ? Stream.empty() : Stream.of(value);
// ofNullable로 위와 같은 기능을 구현
Stream<String> homeValueStream =
Stream.ofNullable(System.getProperty("home"));
// 활용
// home 은 empty 스트리이 만들어짐
Stream<String> valueStreams = Stream.of("os.name", "home", "java.version")
.flatMap(key -> Stream.ofNullable(System.getProperty(key)));
System.out.println(valueStreams.collect(Collectors.joining()));
  • 배열로 스트림 만들기
    • Arrays.stream(int[])
  • 파일로 스트림 만들기
    • java.nio.file.Files 의 수많은 정적 메서드가 스트림을 반환함
Files.lines 스트림 활용 코드
long uniqueWords = 0;
try (Stream<String> lines = Files.lines(
Paths.get("data.txt")),
Charset.defaultCharset())) { // AutoCloseable 활용
uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
.distinct()
.count();
} catch (IOException e) {
// 파일 열때 예외처리
}

함수로 무한 스트림 만들기#

  • iterategenerate 를 사용해 무한 스트림을 만들 수 있음
    • 이런 스트림을 unbounded stream 이라고도 함
  • iterate
    • Stream.iterate(n -> n + 2) 와 같이 사용
    • java9 부터는 iterate에 takeWhile 를 제공하는데, 언제까지 실행할지 지정할 수 있음
  • generate
    • Stream.generate(Math::random) 과 같이 사용
    • 인자로 Supplier<T> 를 받음
  • 스트림을 병렬로 처리하면서 올바른 결과를 얻으려면 불변 상태 기법 을 고수해야 함 (7장에 자세히 나옴)

5.9 마치며#

  • 스트림을 사용하면 복잡한 데이터 처리 질의를 표현 가능
  • filter, distinct, skip, limit 메서드로 필터링하거나 자를 수 있음
  • 소스가 정렬되어 있을때 dropWhile, takeWhile 용이
  • map. flatMap 으로 요소를 추출하거나 변환할 수 있음
  • findFirst, findAny로 스트림 요소 검색 가능
  • allMatch, noneMatch, anyMatch 로 주어진 Predicate와 일치하는 요소를 스트림에서 검색할 수 있음
  • find*, Match 메서드는 쇼트서킷이다
  • reduce로 하나의 값을 도출할 수 있음
  • 상태 없는 연산 (filter, map 등), 상태 있는 연산 (sorted, distinct 등)
  • 기본형 특화 스트림, Int/Double/LongStream
  • 컬렉션, 값, 배열, 파일, iterate/generate 메서드로 스트림을 만들 수 있음
  • 무한한 개수의 요소를 가진 스트림을 무한 스트림이라 함
Last updated on