본문 바로가기
Back-End/Java

스트림

by 달의 조각 2022. 7. 17.

 

다양한 데이터 소스(컬렉션, 배열)를 표준화(컬렉션 프레임웍: 서로 사용법 달랐음)된 방법으로 다룬다

 

선언형으로 데이터 소스를 처리한다

 

 

람다식으로 요소 처리 코드를 제공한다

Stream의 요소 처리 메서드들은 대부분 함수형 인터페이스 매개타입을 가진다
→ 람다식 또는 메서드 참조를 이용해서 요소 처리 내용을 매개값으로 전달 가능하다

 

 

내부 반복자를 사용하므로 병렬 처리가 쉽다

개발자는 요소 처리 코드에만 집중하면 된다!
람다식으로 요소 처리 내용만 전달할 뿐, 반복은 컬렉션 내부에서 일어난다

 

외부 반복자: 개발자가 직접 컬렉션 요소를 반복해서 가져오는 코드 패턴
                     → index를 사용하는 for문, Iterator를 이용하는 while문

내부 반복자: 컬렉션 내부에서 요소들을 반복, 개발자가 요소당 처리할 코드만 제공하는 코드 패턴
                     → 병렬 작업을 할 수 있게 도와주기 때문에 효율적이다 → 병렬 스트림: parallel() 메서드 사용

※ 병렬 작업: 한 가지 작업을 서브 작업으로 나누고, 분리된 스레드에서 병렬적으로 처리하는 것
1. 요소들의 반복 순서 변경
2. 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배

 

 

중간 연산과 최종 연산을 할 수 있다

중간 연산: 매핑, 필터링, 정렬 - 연산 결과가 스트림
최종 연산: 반복, 카운팅, 평균, 총합 등의 집계 - 연산 결과가 스트림이 아님

예: 학생 객체를 요소로 가지는 컬렉션이 있을 때, 중간 연산에서는 학생의 점수를 뽑아 내고, 최종 연산에서는 점수의 평균값을 산출

 

 


 

파이프라인

 

 

여러 개의 스트림이 연결되어 있는 구조, 여러 개의 중간 연산과 하나의 최종 연산
중간 연산을 바로 시행하는 것이 아니라 최종 연산의 시작 전까지는 지연된다

리덕션(Reduction): 대량의 데이터를 가공해서 축소하는 것
                                → 데이터의 합계, 평균값, 카운팅, 최대값, 최소값 등
                                → 컬렉션의 요소를 바로 집계할 수 없을 때에는 중간 연산 필요

 

 

스트림 생성

 

 

1. Read-only
2. 일회용이므로 필요하다면 새로운 스트림을 생성한다

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> listStream = list.stream;
listStream.forEach(System.out::println); //스트림의 모든 요소 출력
//배열 원소를 소스로 하는 Stream: Stream의 of메서드나 Arrays의 stream 메서드 사용
Stream<String> stream = Stream.of("a", "b", "c");
Stream<String> stream = Stream.of(new String[] {"a", "b", "c"});
Stream<String> stream = Arrays.stream(new String[] {"a", "b", "c"});
Stream<String> stream = Arrays.stream(new String[] {"a", "b", "c"}, 0, 3);
IntStream stream = IntStream.range(4, 10); //Intstream의 range()는 for문을 대체한다

 

 

 

중간 연산

 

필터링

· distince(): 데이터 요소의 중복 제거
· filter(): 조건에 맞는 데이터만 정제하여 더 작은 컬렉션 생성, 조건이 참이 되는 요소만 필터링

 

매핑

· map(): 기존의 Stream 요소를 대체하는 요소로 구성된 새로운 Stream을 형성
저장된 값을 특정한 형태로 변환할 때 사용, 인자로 함수형 인터페이스를 받는다
             → mapToInt(), mapToLong(), mapToDouble(), mapToObject 등
             → 스트림의 스트림을 반환 Stream<Stream>

· flatMap(): 요소를 대체하는 복수 개의 요소들로 구성된 새로운 Stream을 리턴
             → 스트림을 반환 Stream

 

정렬

· sorted(): 오름차순 정렬, 파라미터로 Comparator를 넘길 수도 있다
                내림차순으로 정렬하기 위해서는 Comparator의 reverseOrder를 이용
                Comparable을 기본적으로 구현한 클래스가 아니라면, comparing() 메서드를 사용해 비교

 

연산 결과 확인

· peek(): 중간 연산 메서드,  하나의 스트림에 여러 번 사용 가능, 주로 연산 중간에 결과를 확인하여 디버깅하고자 할 때 사용
· forEach는 최종 연산 메서드, 스트림의 요소를 소모하므로 한 번만 호출 가능

 

 

 

최종 연산

 

연산 결과가 스트림이 아니므로, 한 번만 연산이 가능

 

연산 결과 확인

· forEach(): 파이프라인 마지막에서 요소를 하나씩 연산, 출력할 때도 사용하지만, 이메일 발송, 스케줄링 등 리턴 값이 없는 작업에서도 많이 사용

 

매칭

match()

1. 요소들이 특정한 조건을 충족하는지 검사하고 싶은 경우
2. 함수형 인터페이스 Predicate를 받아서 조건을 만족하는지 검사
3. 결과를 boolean으로 반환

· allMatch() : 모든 요소가 조건을 만족하는지 조사
· anyMatch() : 최소한 한 개의 요소가 조건을 만족하는지 조사
· noneMatch() : 모든 요소가 조건을 만족하지 않는지 조사

 

기본 집계

· sum()
· count()
· average()
· max()
· min()

 

Reduce

누적하여 하나로 응축(reduce)하는 방식으로 동작, 최대 3개의 매개변수를 받을 수 있다

· Accumulator: 각 요소를 계산한 중간 결과를 생성하기 위해 사용
· Identity: 계산을 수행하기 위한 초기값
· Combiner: 병렬 스트림(Parlallel Stream)에서 나누어 계산된 결과를 하나로 합치기 위한 로직

 

Collect()

요소들을 List나 Set, Map 등 다른 종류의 결과로 수집하고 싶은 경우

어떻게 Stream의 요소들을 수집할 것인가를 정의한 Collector 타입을 인자로 받는다
이는 Collector 인터페이스를 구현한 클래스입니다.

일반적으로 List로 Stream의 요소들을 수집하는 경우가 많다
자주 사용하는 작업은 Collectors 객체에서 static 메서드로 제공하고 있고,
원하는 것이 없는 경우에는 Collector 인터페이스를 직접 구현하여 사용할 수도 있다

 

 

Optional<T>

 

NullPointerException(NPE)을 방지한다

 

Optional

모든 타입의 객체를 담을 수 있는 래퍼 클래스, 메서드 체이닝 가능

· of() : Optional 객체 생성
· ofNullable() : Optional 객체 생성, 참조변수 값이 null일 가능성이 있을 때
· isPresent() : Optional 객체의 값이 null인가?
· empty() : 참조변수를 기본값으로 초기화
· get()
· orElse(): null일 가능성이 있을 때 디폴트 값 지정

'Back-End > Java' 카테고리의 다른 글

스레드(Thread)  (0) 2022.07.19
파일 입출력(I/O)  (0) 2022.07.18
람다  (0) 2022.07.16
배열 문제 풀이  (0) 2022.07.06
조건문과 반복문 문제 풀이  (0) 2022.07.05

댓글