자바

자바 - 스트림 요소 처리

록's 2023. 1. 27. 18:17
728x90
반응형

List<String> list = ................;
for(int i=0; i<list.size(); i++){
String item = list.get(i);
// item 처리
}

Set<String> set = ...............;
Iterator<String> iterator = set.iterator();
while(iter.hasNext()) {
String item = iterator.next()
// 요소 처리
}

// STREAM 처리
Stream<String> stream = list.stream();
stream.forEach(item -> // item 처리);


기존 JAVA에서 컬렉션 데이터를 처리할떄 특정 조건에 따라 필터링을 하려면 복잡한 과정을 거쳐야 한다.
반면에 SQL 문법의 경우 사용자가 원하는 조건의 데이터 목록을 검색할 때 명시적이고 간단한 방법을 이용하는데 JAVA 8에서 새로 추가된
기능인 스트림은 JAVA의 컬렉션 데이터에 대해 SQL 질의문처럼 데이터를 처리 할 수 있는 기능을 가진다.

기존 루프문 처리의 문제점
기존 JAVA에서 컬렉션 데이터를 처리할 떄는 for, foreach 루프문을 사용하면서 컬렉션 내의 요소들을 하나씩 다룬다.
간단한 처리나 컬렉션의 크기가 작으면 큰 문제가 아니지만 복잡한 처리가 필요하거나 컬렉션의 크기가 커지면 루프문의 사용은 성능저하를
이르키게 된다.

 

스트림
스트림은 컬렉션 데이터를 선언형으로 쉽게 처리할 수 있다. 복잡한 루프문을 사용하지 않아도 되며 루프문을 중첩해서 사용해야 되는 최악의 경우도 없어지게 된다. 또한 스트림은 병렬처리(Multi thread)를 별도의 멀티스레드 구현없이도 쉽게 구현이 가능하다.

 

Iterator : 외부 반복자 : 개발자 코드에서 컬렉션의 요소를 하나 가져와서 처리하고 다시 컬렉션의 요소를 하나 가져와서 처리
stream : 내부 반복자 : 개발자 코드에서 컬렉션의 요소를 하나씩 처리, 컬렉션의 요소를 하나씩 처리
Stream은 Iterator 와 비슷한 반복자이지만 다음과 같은 차이점을 가지고있다.
1) 내부 반복자이므로 처리 속도가 빠르고 병렬 처리에 효율적이다.
2) 람다식으로 다양한 요소 처리를 정의 할 수 있다
3) 중간 처리와 최종 처리를 수행하도록 파이프 라인을 형성 할 수 있다.

 

 

Comparable과 Comparator는 둘 다 인터페이스
정렬에 사용
객체를 비교할 수 있다.

Comparable : compareTo 메서드 구현
자기 자신과 매개변수 객체를 비교
compareTo( T o)

Comparator : compare 메서드 구현
두 매개변수 객체를 비교
compare( T o1, T o2)


Optional 클래스
java.util.Optional<T>
Optional은 선택형 값을 캡슐화하는 클래스이다.
값이 있으면 Optional 클래스는 값을 감싼다.
값이 없으면 Optional.empty 메서드로 Optional을 반환한다.

기본 타입 래퍼클래스 (Wrapper class)
byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double -> Double
char -> Char
boolean -> Boolean
기본타입의 데이터를 객체로 취급해야 하는 경우
메서드의 인수로 객체 타입만이 요구되며, 기본 타입의 데이터를 그대로 사용할 수 가 없다.
이때 기본타입의 데이터를 객체로 변환한 후 작업을 수행해야 한다.


값이 없을 경우 디폴트 값을 설정하거나 집계값을 처리하는 Consumer를 등록 할 수 있다.

isPresent() 메서드가 true를 리턴 할 때만 집계값을 얻는다.
orElse() 메서드로 집계값이 없을 경우를 대비해서 디폴트 값을 정해 놓는다.
ifPresent() 메서드로 집계값이 있을 경우에만 동작하는 Consumer 람다식을 제공한다,

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

orElse() 메서드로 집계값이 없을 경우를 대비해서 디폴트 값을 정해 놓는다.

double avg = stream.
.average()
.orElse(0,0);
System.out.println("평균 : " + avg);

ifPresent() 메서드로 집계값이 있을 경우에만 동작하는 Consumer 람다식을 제공한다.

stream
.average()
.ifPresent(a -> System.out.println("평균: " + a);


reduce()
int sum = stream
.reduce((a,b) -> a+b)
.getAsInt();
값이 있을때 정상 동작
값이 없을때 예외 발생 (NoSuchElementException) 예외발생

int sum = stream
.reduce(0, (a, b) -> a+b)
.getAsInt();
매개 값이 있을 경우, a와 b를 더한 값이 리턴
매개 값이 없을 경우 0 -> 리턴 0
 


스트림이란?

 

 

스트림

  • Java 8부터 컬렉션 및 배열의 요소를 반복 처리하기 위해 스트림 사용
  • 요소들이 하나씩 흘러가면서 처리된다는 의미

  • List 컬렉션의 stream() 메소드로 Stream 객체를 얻고, forEach() 메소드로 요소를 어떻게 처리할지를 람다식으로 제공
  • 스트림과 Iterator 차이점
    • 1) 내부 반복자이므로 처리 속도가 빠르고 병렬 처리에 효율적
    • 2) 람다식으로 다양한 요소 처리를 정의
    • 3) 중간 처리와 최종 처리를 수행하도록 파이프 라인을 형성

 

내부 반복자

 

 

내부반복자

  • 요소 처리 방법을 컬렉션 내부로 주입시켜서 요소를 반복 처리
  • 개발자 코드에서 제공한 데이터 처리 코드(람다식)를 가지고 컬렉션 내부에서 요소를 반복 처리
  • 내부 반복자는 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배시켜 병렬 작업 가능

 

 

 

 

중간 처리와 최종 처리

 

 

스트림 파이프라인

  • 컬렉션의 오리지널 스트림 뒤에 필터링 중간 스트림이 연결될 수 있고, 그 뒤에 매핑 중간 스트림이 연결될 수 있음

  • 오리지널 스트림과 집계 처리 사이의 중간 스트림들은 최종 처리를 위해 요소를 걸러내거나(필터링), 요소를 변환시키거나(매핑), 정렬하는 작업을 수행
  • 최종 처리는 중간 처리에서 정제된 요소들을 반복하거나, 집계(카운팅, 총합, 평균) 작업을 수행

 

 

 

 

 

스트림 인터페이스

  • java.util.stream 패키지에는 BaseStream 인터페이스를 부모로 한 자식 인터페이스들은 상속 관계
  • BaseStream에는 모든 스트림에서 사용할 수 있는 공통 메소드들이 정의

 

 

 

 

컬렉션으로부터 스트림 얻기

  • java.util.Collection 인터페이스는 스트림과 parallelStream() 메소드를 가지고 있어 자식 인터페이스인 List와 Set 인터페이스를 구현한 모든 컬렉션에서 객체 스트림을 얻을 수 있음

 

배열로부터 스트림 얻기

  • java.util.Arrays 클래스로 다양한 종류의 배열로부터 스트림을 얻을 수 있음

 

숫자 범위로부터 스트림 얻기

  • IntStream 또는 LongStream의 정적 메소드인 range()와 rangeClosed() 메소드로 특정 범위의 정수 스트림을 얻을 수 있음

파일로부터 스트림 얻기

  • java.nio.file.Files의 lines() 메소드로 텍스트 파일의 행 단위 스트림을 얻을 수 있음

 

 

 

 

 

요소 걸러내기(필터링)

 

 

필터링

  • 필터링은 요소를 걸러내는 중간 처리 기능

  • distinct() 메소드: 요소의 중복을 제거

  • filter() 메소드: 매개값으로 주어진 Predicate가 true를 리턴하는 요소만 필터링

  • Predicate: 함수형 인터페이스

  • 모든 Predicate는 매개값을 조사한 후 boolean을 리턴하는 test() 메소드를 가지고 있다.

 

 

 

 

 

요소 변환(매핑)

 

 

매핑

  • 스트림의 요소를 다른 요소로 변환하는 중간 처리 기능
  • 매핑 메소드: mapXxx(), asDoubleStream(), asLongStream(), boxed(), flatMapXxx() 등

 

요소를 다른 요소로 변환

  • mapXxx() 메소드: 요소를 다른 요소로 변환한 새로운 스트림을 리턴

  • 매개타입인 Function은 함수형 인터페이스

  • 모든 Function은 매개값을 리턴값으로 매핑(변환)하는 applyXxx() 메소드를 가짐

  • 기본 타입 간의 변환이거나 기본 타입 요소를 래퍼(Wrapper) 객체 요소로 변환하려면 간편화 메소드를 사용할 수 있음

 

 

 

 

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

  • flatMapXxx() 메소드: 하나의 요소를 복수 개의 요소들로 변환한 새로운 스트림을 리턴

 

 

 

요소 정렬

 

 

정렬

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

 

 

Comparable 구현 객체의 정렬

  • 스트림의 요소가 객체일 경우 객체가 Comparable을 구현하고 있어야만 sorted() 메소드를 사용하여 정렬 가능. 그렇지 않다면 ClassCastException 발생

 

 

Comparator를 이용한 정렬

  • 요소 객체가 Comparable을 구현하고 있지 않다면, 비교자를 제공하면 요소를 정렬시킬 수 있음

  • 괄호 안에는 o1이 o2보다 작으면 음수, 같으면 0, 크면 양수를 리턴하도록 작성
  • o1과 o2가 정수일 경우에는 Integer.compare(o1, o2)를, 실수일 경우에는 Double.compare(o1, o2)를 호출해서 리턴값을 리턴 가능

 

 

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

 

 

루핑

  • 스트림에서 요소를 하나씩 반복해서 가져와 처리하는 것

  • 매개타입인 Consumer는 함수형 인터페이스. 모든 Consumer는 매개값을 처리(소비)하는
    accept() 메소드를 가지고 있음

 

 

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

 

 

매칭

  • 요소들이 특정 조건에 만족하는지 여부를 조사하는 최종 처리 기능
  • allMatch(), anyMatch(), noneMatch() 메소드는 매개값으로 주어진 Predicate가 리턴하는 값에 따라 true 또는 false를 리턴
 
 

 

요소 기본 집계

 

집계

  • 최종 처리 기능으로 요소들을 처리해서 카운팅, 합계, 평균값, 최대값, 최소값 등 하나의 값으로 산출하는 것
 

스트림이 제공하는 기본 집계

  • 스트림은 카운팅, 최대, 최소, 평균, 합계 등을 처리하는 다음과 같은 최종 처리 메소드를 제공

 
 

Optional 클래스

  • Optional, OptionalDouble, OptionalInt, OptionalLong 클래스는 단순히 집계값만 저장하는 것이 아니라, 집계값이 없으면 디폴트 값을 설정하거나 집계값을 처리하는 Consumer를 등록
 

최종 처리에서 average 사용 시 요소 없는 경우를 대비하는 방법

  1. isPresent() 메소드가 true를 리턴할 때만 집계값을 얻는다.
  2. orElse() 메소드로 집계값이 없을 경우를 대비해서 디폴트 값을 정해놓는다.
  3. ifPresent() 메소드로 집계값이 있을 경우에만 동작하는 Consumer 람다식을 제공한다.
 

요소 커스텀 집계

 

스트림이 제공하는 메소드

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

  • reduce()는 스트림에 요소가 없을 경우 예외가 발생하지만, identity 매개값이 주어지면 이 값을 디폴트 값으로 리턴
 
 
 

요소 수집

 

필터링한 요소 수집

  • Stream의 collect(Collector<T,A,R> collector) 메소드는 필터링 또는 매핑된 요소들을 새로운 컬렉션에 수집하고, 이 컬렉션을 리턴
  • 매개값인 Collector는 어떤 요소를 어떤 컬렉션에 수집할 것인지를 결정
  • 타입 파라미터의 T는 요소, A는 누적기accumulator, 그리고 R은 요소가 저장될 컬렉션
 

 

 

요소 그룹핑

  • Collectors.groupingBy () 메소드에서 얻은 Collector를 collect() 메소드를 호출할 때 제공
  • groupingBy()는 Function을 이용해서 T를 K로 매핑하고, K를 키로 해 List<T>를 값으로 갖는 Map 컬렉션을 생성
  • Collectors.groupingBy() 메소드는 그룹핑 후 매핑 및 집계(평균, 카운팅, 연결, 최대,최소, 합계)를 수행할 수 있도록 두 번째 매개값인 Collector를 가질 수 있음
 
 

 

요소 병렬 처리

 

동시성과 병렬성

  • 동시성: 멀티 작업을 위해 멀티 스레드가 하나의 코어에서 번갈아 가며 실행하는 것
  • 병렬성: 멀티 작업을 위해 멀티 코어를 각각 이용해서 벙렬로 실행하는 것

  • 데이터 병렬성: 전체 데이터를 분할해서 서브 데이터셋으로 만들고 이 서브 데이터셋들을 병렬 처리해서 작업을 빨리 끝내는 것
  • 작업 병렬성: 서로 다른 작업을 병렬 처리하는 것
 

 

포크조인 프레임워크

  • 포크 단계: 전체 요소들을 서브 요소셋으로 분할하고, 각각의 서브 요소셋을 멀티 코어에서 병렬로 처리
  • 조인 단계: 서브 결과를 결합해서 최종 결과를 만들어냄

  • 포크조인 프레임워크는 ExecutorService의 구현 객체인 ForkJoinPool을 사용해서 작업 스레드를 관리

 

 
 

병렬 스트림 사용

  • 자바 병렬 스트림은 백그라운드에서 포크조인 프레임워크가 사용하므로 병렬 처리 용이
  • parallelStream() 메소드는 컬렉션(List, Set)으로부터 병렬 스트림을 바로 리턴
  • parallel() 메소드는 기존 스트림을 병렬 처리 스트림으로 변환

 

병렬 처리 성능에 영향을 미치는 요인

  • 요소의 수와 요소당 처리 시간
  • 스트림 소스의 종류
  • 코어(Core)의 수
 
728x90
반응형

'자바' 카테고리의 다른 글

자바 - 네트워크 입출력  (0) 2023.01.31
자바 - 데이터 입출력  (0) 2023.01.30
자바 - 람다식  (0) 2023.01.27
자바 - 컬렉션 자료구조  (0) 2023.01.25
자바 - 멀티 스레드  (0) 2023.01.25