Java[이것이 자바다 CH17]

이도환·2023년 8월 22일
post-thumbnail

스터디 링크
코드 링크

스트림 요소 처리

17.1 스트림이란?

  • 스트림은 요소들이 하나씩 흘러가면서 처리된다는 의미를 가지고 있다. list컬렉션에서 요소를 반복 처리하기 위해 스트림을 사용하면 다음과 같다.
Stream<String> stream = list.stream();
stream.forEach( item -> //아이템 처리);

Streamlterator와 비슷한 반복자지만, 다음과 같은 차이점을 가지고 있다.

  1. 내부 반복자 이므로 처리 속도가 빠르고 병렬 처리에 효율적이다.
  2. 람다식으로 다양한 요소 처리를 정의할 수 있다.
  3. 중간 처리와 최종 처리를 수행하도록 파이프라인을 형성할 수 있다.

17.2 내부 반복자

  • 스트림은 요소 처리 방법을 컬렉션 내부로 주입시켜서 요소를 반복 처리하는데, 이것을 내부 반복자라고 한다. 다음 그림을 보면서 외부 반복자와 내부 반복자를 이해해보자

    내부 반복자일 경우 개발자 코드에서 제공한 데이터 처리 코드를 가지고 컬렉션 내부에서 요소를 반복 처리 한다.
    내부 반복자는 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배시켜 병렬 작업을 할 수 있다.

17.3 중간 처리와 최종 처리

  • 스트림은 하나 이상 연결될 수 있다. 오리지날 스트림 뒤에 필터링 중간 스트림이 연결될 수 있고, 그 뒤에 매핑 중간 스트림이 연결될 수 있다. 이것을 스트림의 파이프라인이라고 한다.

    최종처리 전의 스트림들을 요소를 걸러내거나 변환, 정렬 시키는데 사용되며 최종 처리는 정제된 요소들을 반복하거나 집계 작업을 수행한다.

17.4 리소스로부터 스트림 얻기

  • java.util.stream패키지에는 스트림 인터페이스들이 있다. BaseStream인터페이스를 부모로 한 자식 인터페이스들은 다음과 같은 상속 관계이다.


    위와 같은 리소스로부터 스트림 구현 객체를 얻을 수도 있다.
  • 컬렉션으로부터 스트림 얻기
    java.util.Collection인터페이스는 스트림과 parallelStream() 메소드를 가지고 있기 때문에 자식 인터페이스인 List, Set 인터페이스를 구현한 모든 컬렉션에서 객체 스트림을 얻을 수 있다.
  • 숫자 범위로부터 스트림 얻기
    IntStream, LongStream의 정적 메소드인range(),rangeClosed()메소드를 이용하면 특정 범위의 정수 스트림음 얻을 수 있다. 첫 번째 매개값은 시작수이고 두번째 매개 값은 끝 수인데, 끝 수를 포함하지 않으면 range() 포함하면 rangeClosed()
  • 파일로부터 스트림 얻기
    java.nio.file.Files의 line()메소드를 이용하면 텍스트 파일의 행 단위 스트림을 얻을 수 있다. 이는 텍스트 파일에서 한 행씩 읽고 처리할 때 유용하게 사용할 수 있다.

17.5 요소 걸러내기(필터링)

  • 필터링은 요소를 걸러내는 중간 처리 기능이다. distinct()``filter()가 있다.

    distinct()메소드는 요소의 중복을 제거한다. 객체 스트림일 경우 equals()의 리턴값이 true이면 동일한 요소로 판단한다.

    filter()메소드는 매개값으로 주어진 predicate가 true를 리턴하는 요소만 필터링한다.

    Predicate는 함수현 인터페이스이고 종류는 다음과 같다.

17.6 요소 변환(매핑)

  • 매핑은 스트림의 요소를 다른 요소로 변환하는 중간 처리 기능이다.

  • 요소를 복수 개의 요소로 변환

    flatMap()메소드의 종류

17.7 요소 정렬

  • 정렬은 요소를 오름차순 또는 내림차순으로 정렬하는 중간 처리 기능이다.

  • Comparable 구현 객체의 정렬
    Comparable을 구현하고 있어야만 sorted() 메소드를 사용하여 정렬할 수 있다.

  • Comparator를 이용한 정렬

17.8 요소를 하나씩 처리(루핑)

  • 루핑은 스트림에서 요소를 하나씩 반복해서 가져와 처리하는 것을 말한다. 루핑 메소드는 peek()``forEach()가 있다.

    peek과 forEach는 동일하게 요소를 루핑하지만 중간처리 메소드, 최종 처리 메소드라는 점에서 차이가 있다. 따라서 peek()은 최종 처리가 뒤에 붙지 않으면 동작히자 않는다.

17.9 요소 조건 만족 여부(매칭)

  • 매칭은 요소들이 특정 조건에 만족하는지 여부를 조사하는 최종 처리 기능이다.

17.10 요소 기본 집계

  • 집계는 최종 처리 기능으로 요소들을 처리해서 카운팅, 합계, 평균값, 최대값, 최소값 등과 같은 하나의 값으로 산출하는 것을 말한다.
  • 스트림이 제공하는 기본 집계
  • Optional 클래스
    위 클래스는 집계값이 존재하지 않을 경우 디폴트 값을 설정하고나 집계값을 처리하는 Consumer를 등록할 수 있다.

    ex)isPresent()메소드 예시

OptionalDouble optional = stream
 .average();
if(optional.isPresent()) {
	System.out.println("평균: " + optional.getAsDouble());
    } else {
      System.out.println(" 평균: 0.0");

17.11 요소 커스텀 집계

  • 스트림은 기본 집계 메소드인 sum, average, count, max, min을 제공하지만, 다양한 집계 결과물을 만들 수 있도록 reduce() 메소드도 제공한다.

17.12 요소 수집

  • 스트림은 요소들을 필터링 또는 매핑한 후 요소들을 수집하는 최종 처리 메소드인 collect()를 제공한다. 이 메소드를 이용하면 필요한 요소만 컬렉션에 담을 수 있고, 요소들을 그룹핑한 후에 집계도 할 수 있다.
  • 필터링한 요소 수집
List<Student> maleList = totalList.stream()
.filter(s- >s.getSex().equals("남"))
.collect(Collectors.toList());
Map<String, Interger> map = totalList.stream()
.collect(
 Collectors.toMap(
  s -> s.getName(),
  s -> s.getScore()
  )
 );
  • 요소 그룹핑
    collect()메소드는 단순히 요소를 수집하는 기능 이외에 컬렉션의 요소들을 그룹핑해서 Map객체를 생성하는 기능도 제공한다.
Map<String, List<Student>> map = totalList.stream()
.collect(
 Collectors.groupingBy(s ->s.getSex())
);

17.13 요소 병렬 처리

  • 요소 병렬 처리란 멀티 코어 CPU환경에서 전체 요소를 분할 해서 각각의 코어가 병렬적으로 처리하는 것을 말한다. 요소 병렬 처리의 목적은 작업 처리 시간을 줄이는 것에 있다.
  • 동시성과 병렬성
    멀티 스레드는 동시성 또는 병렬성 으로 실행되기 때문에 이들 용어에 대해 정확히 이해하는 것이 좋다. 동시성은 멀티 작업을 위해 멀티 스레드가 하나의 코어에서 번갈아 가며 실행하는 것을 말하고, 병렬성은 멀티 작업을 위해 멀티 코어를 각각 이용해서 병렬로 실행하는 것을 말한다.
  • 포크조인 프레임 워크
    자바 병렬 스트림은 요소들을 병렬 처리하기 위해 포크 조인 프레임워크를 사용한다. 포크 단계에서 전체 요소들을 서브 요소셋으로 분할하고, 각각의 서브 요소셋을 멀티 코어에서 병렬로 처리한다. 조인 단계에서는 서브 결과를 결합해서 최종 결과를 만들어낸다.
  • 병렬 스트림 사용
    자바 병렬 스트림을 이용할 경우에는 백그라운드에서 포크 조인 프레임워크가 사용되기 때문에 개발자는 매우 쉽게 병렬처리를 할 수 있다. 병렬 스트림은 다음 두가지 메소드로 얻을 수 있다.
Stream<Integer> stream = scores.parallestream();
startTime = System.nanoTime();
avg = stream
.mapToInt(i -> i.intValue())
.average()
.getAsDouble();
endTime = System.nanoTime();
time = endTime - StartTime;

위와 같은 병렬 스트립 코드는 일반 스트림 코드보다 런타임이 짧음을 코드의 결과로 알 수 있었다.

profile
개발 블로그

2개의 댓글

comment-user-thumbnail
2023년 8월 23일

스터디 링크와 코드 링크 모두 에러가 뜹니다 ㅠㅠㅠㅠㅠ 그래도 좋은 글 감사합니다~~~ 항상 보고 배우고 있습니다!!

1개의 답글