[자바의 정석] 14. 람다와 스트림 - 스트림, 스트림의 특징

jyleever·2022년 9월 25일
0

자바의 정석

목록 보기
8/12
post-thumbnail
post-custom-banner

스트림

  • 데이터의 연속적인 흐름

다양한 데이터 소스(Collection, 배열 등과 같이 여러 데이터를 저장하고 있는 것)를 표준화된 방법으로 다루기 위한 것

  • List, Set, Map 의 성격이 다르기 때문에 표준화하기 어려운데 stream이 등장하면서 표준화될 수 있음
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

Stream<Integer> intStream = list.stream(); // 컬렉션
Stream<Integer> strStream = Stream.of(new String[]{"a", "b", "c"}; // 배열
Stream<Integer> evenStream = Stream.iterate(0, n->n+2); // 0 , 2, 4, 6 ...
Stream<Double> randomStream = Stream.generate(Math::random); // 람다식
IntStream intStream = new Random().ints(5); //난수 스트림(크기가 5)

컬렉션이나 배열과 같은 다양한 데이터 소스를 Stream으로 만들면 똑같은 방식으로 작업을 처리할 수 있다.

Stream 으로 작업을 처리하기
1. 스트림으로 변환
2. 0 ~ N번의 중간 연산
3. 1번의 최종 연산

중간 연산은 여러 번, 최종 연산은 딱 1번 할 수 있다.
데이터소스마다 달랐던 작업 방식을 stream으로 바뀌면서 같은 방식으로 처리할 수 있다.

  • Collection에 Stream 이라는 메서드가 있다.
    컬렉션에 있는 Stream 메서드를 호출하면 Collection을 Stream으로 변환해 반환해준다. 이런 식으로 모든 데이터 소스를 Stream으로 바꿔줄 수 있다~

스트림 파이프라인

스트림은 데이터의 필터링, 매핑, 정렬, 그룹핑 등의 중간 처리와 합계, 평균, 카운팅, 최댓값 등의 최종 파이프라인으로 해결한다.
여기서 파이프라인은 컴퓨터 과학에서 한 데이터 처리 단계의 출력이 다음 단계의 입력으로 이어지는 형태로 연결된 구조
오리지널 스트림 - 중간 처리(필터링 처리, 매핑 처리 등) - 최종 처리

스트림이 제공하는 기능 - 중간 연산과 최종 연산

  • 중간 연산 - 연산 결과가 스트림인 연산. 반복적으로 이어서 적용 가능
  • 최종 연산 - 연산 결과가 스트림이 아닌 연산. 단 한 번만 적용 가능(스트림의 요소를 소모)
stream.distinct().limit(5).sorted().forEach(System.out.println)
중간 연산 : distinct(), limit(5), sorted()
최종 연산 : forEach(System.out::println) 하나씩 꺼내서 출력..
String[] strArr = { "dd", "aaa", "CC", "cc", "b" };
Stream<String> stream = Stream.of(strArr); // 문자열 배열이 소스인 스트림
Stream<String> filteredStream = stream.filter(); // 걸러내기 (중간 연산)
Stream<String> distinctedStream = stream.distinct(); // 중복 제거  (중간 연산)
Stream<String> sortedStream = stream.sort(); // 정렬 (중간 연산)
Stream<String> limitedStream = stream.limit(5); // 스트림 자르기 (중간 연산)
int total = stream.count(); // 요소 개수 세기 (최종 연산)

스트림의 특징 (1/3)

스트림은 데이터 소스로부터 데이터를 읽기만 할 뿐, 변경하지 않는다
Read Only

List<Integer> list = Arrays.asList(3, 1, 5, 4, 2);
List<Integer> sortedList = list.stream().sorted() // list를 정렬해서
								.collect(Collectors.toList()); // 새로운 List에 저장
System.out.println(list); // [3, 1, 5, 4, 2]
System.out.println(sortedList); // [1, 2, 3, 4, 5];

스트림은 Iterator처럼 일회용이다. 필요하면 다시 스트림을 생성해야 함!

strStream.forEach(System.out::println); // 모든 요소를 화면에 출력
(최종 연산 - Stream의 요소를 소모, 즉 최종 연산 후에는 스트림이 닫힘)
int numOfStr = strStream.count(); // 에러! 스트림이 이미 닫힘~~

최종 연산 전까지 중간 연산이 수행되지 않는다. - 지연된 연산

IntStream intStream = new Random().ints(1, 46); // 1~45 범위의 난수를 발생시키는 무한 스트림. 즉 스트림의 요소의 개수를 가지고 올 수 없다!
intStream.distinct().limit(6).sorted() // 중간 연산
			.forEach(i->System.out.print(i+",")); // 최종 연산

무한 스트림에서 중복 제거를 할 수 있는 것은 아니지만 이런 코드가 가능하다. 이 Stream을 가지고 어떤 작업을 해야 하는지 체크만 해놨다가, 필요할 때 나중에 수행한다.
이것을 바로 지연된 연산 이라고 함! 지연된 연산 덕분에 이런 코드 작성이 가능하다.

스트림의 특징 (2/3)

스트림은 작업을 내부 반복으로 처리한다.

for(String str : strList)
	System.out.println(str);

위 코드를 다음과 같이 바꿀 수 있다. 코드가 매우 간결해짐~

stream.forEach(System.out::println);

forEach

void forEach(Consumer<? super T> action){
	Objects.requireNonNull(action); // 매개변수의 널 체크
    for(T t : src) // 내부 반복 (for문을 메서드 안으로 넣음)
    	action.accept(T);

스트림의 특징 (3/3)

스트림의 작업을 병렬로 처리 - 병렬 스트림
스트림을 병렬 스트림으로 변환하는 것.
멀티 쓰레드로 병렬 처리한다는 뜻이다. 람다는 함수형 언어의 특징이라고 했음... 함수형 언어의 특징? 빅데이터 처리하기 용이. 즉 병렬로 처리 하기 용이~

Stream<String> strStream = Stream.of("dd", "aaa", "CC", "cc", "b");
int sum = strStream.parallel() // 병렬 스트림으로 전환(속성만 변경)
			.mapToInt(a -> s.length()).sum(); // 모든 문자열의 길이의 합    

parallel로 메서드 호출만 하고 그 다음 작업은 똑같이 처리. 즉 병렬로 처리하여 더 빠르게 결과를 얻을 수 있음
스트림 -> 병렬 스트림, 병렬 스트림에서 스트림으로 변환하는 것은 Sequential()

기본형 스트림 - IntStream, LongStream, DoubleStream
1. 오토 박싱 & 언박싱의 비효율이 제거됨 (Stream<Integer> 대신 IntStream 사용) - 기본형 스트림을 사용하는 이유

  • 스트림으로 변환하면 기본형에서 참조형으로 바뀌어서 Stream에 저장된다. -> 오토 박싱 1 -> new Integer(1)
  • 하지만 데이터가 많으면 이런 처리 하나하나가 시간이 오래 걸려 성능이 느리다. 따라서 Stream<Integer> 대신 IntStream을 사용하면 오토 박싱&언박싱의 비효율이 제거할 수 있다.
    항상 사용할 수 있는 것은 아니고, 데이터 소스가 기본형일 때 사용할 수 있다.
  1. 숫자와 관련된 유용한 메서드를 Stream<T>보다 더 많이 제공
  • T는 어떤 타입인지 모르므로 count 정도만 제공 그러나 IntStream , LongStream 등은 숫자인지 알고 있으므로 sum, average 등의 관련 메서드를 제공한다는 장점이 있다
  • 기본형 스트림은 몰라도 되지만.. 성능을 개선하고 싶을 때 이 기본형 스트림을 사용한다.
post-custom-banner

0개의 댓글