본문 바로가기

프로그래밍/Java

[Java 요약 정리] 11. 스트림(Stream)

11. 스트림(Stream)


1) 스트림이란?

- 다양한 데이터 소스를 통일된 방법으로 다루기 위한 것

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

- 과정: 스트림 생성 -> 중간연산 -> 최종연산


2) 스트림의 특징

- 스트림은 데이터 소스로부터 데이터를 읽기만할 뿐 변경하지 않음(원본 유지)

- 스트림은 Iterator처럼 일회용(필요시 스트림 재 생성해서 사용)

- 최종 연산 전까지 중간연산 미수행(지연된 연산)

- 작업을 내부 반복으로 처리한다.

- 작업을 병렬처리한다. (병렬 스트림)

*기본형 스트림(IntStream, LongStream, DoubleStream)

- 오토박싱&언박싱의 비효율 제거됨(Stream<Integer> 대신 IntStream사용)

- 숫자와 관련된 유용한 메소드를 Stream<T>보다 많이 제공


3) 스트림의 생성

- 컬렉션으로부터 스트림 생성

List<Integer> 참조변수 = Arrays.asList(1,2,3,4,5);

Stream<Integer> intStream = List.stream();


- 배열로부터 스트림 생성

Stream<String> strStream = Stream.of("a","b","c"); // 가변인자

Stream<String> strStream = Arrays.Stream(new String[]{"a","b","c"});


- 특정 범위의 정수를 요소로 갖는 스트림 생성

IntStream intStream = IntStream.range(1, 5); // range 끝 값 미포함, rangeClosed 끝 값 포함


- 난수를 요소로 갖는 스트림 생성

IntStream intStream = new Random().ints(); // 무한 스트림

intStream.limit(5).forEach(System.out::println); // 5개 요소 출력

IntStream intStream = new Random().ints(5); // 크기가 5인 난수 스트림을 반환

*유한생성자: ints(long streamSize, int begin, int end) // 유한 스트림

*무한생성자: ints(int begin, int end) // 무한 스트림


- 람다식을 소스로 하는 스트림 생성

static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) // 이전 요소에 종속

static <T> Stream<T> generate(Supplier<T> s) // 이전 요소에 독립


- 파일을 소스로 하는 스트림 생성

Stream<Path> Files.list(Path dir) // 매개변수: 파일 혹은 디렉토리


4) 스트림의 중간연산 메소드

- 스트림 자르기

skip(long n) -> 앞에서부터 n개 건너뛰기

limit(maxSize) -> maxSize 이후 요소 잘라냄


- 스트림의 요소 걸러내기

filter(Predicate<? super T> predicate) -> 조건에 맞지 않는 요소 제거

distinct() -> 중복 제거


- 스트림 정렬하기 sorted()의 매개변수

기본정렬: (Comparator.naturalOrder()), ((s1, s2) -> s1.compareTo(s2)), (String::compareTo)

역순정렬: (Comparator.reverseOrder()), (Comparator.<String>naturalOrder().reversed())

대소문자미구분: (String.CASE_INSENSITIVE_ORDER) // reversed()로 역순 정렬 가능

길이순정렬: (Comparator.comparing(String::length)) // comparingInt -> no 오토박싱


- 스트림의 요소 변환

map(Function<? super T, ? extends R> mapper) -> Stream<T> -> Stream<R>


- 스트림 요소 소모 없이 조회

peek() -> forEach랑 같은 형식


5) 스트림 타입 변환 표


스트림 타입 변환 정리표

From

To

변환 메소드

스트림 -> 기본형 스트림

Stream<T>

IntStream

LongStream

DoubleStream

MapToInt (Function<T> mapper)

mapToLong (ToLongFunction<T> mapper)

mapToDouble(ToDoubleFunction<T>mapper)

기본형 스트림 -> 스트림

IntStream

LongStream

DoubleStream

Stream<Integer>

Stream<Long>

Stream<Double>

boxed()

Stream<U>

mapToObj (DoubleFunction<U> mapper)

기본형 스트림 -> 기본형 스트림

Stream<T>

IntStream

LongStream

DoubleStream

asLongStream()

asDoubleStream()

스트림 -> 부분 스트림

Stream<T>

IntStream

Stream<T>

IntStream

skip (long n)

limit (long maxSize)

두 개의 스트림 -> 스트림

Stream<T>, Stream<T>

Stream<T>

concat (Stream<T> a, Stream<T> b)

IntStream, IntStream

IntStream

concat (IntStream a, IntStream b)

LongStream, LongStream

LongStream

concat (LongStream a, LongStream b)

DoubleStream, DoubleStream

DoubleStream

concat (DoubleStream a, DoubleStream b)

스트림의 스트림 -> 스트림

Stream<Stream<T>>

Stream<T>

flatMap (Function mapper)

Stream<IntStream>

IntStream

flatMapToInt (Function mapper)

Stream<LongStream>

LongStream

flatMapToLong (Function mapper)

Stream<DoubleStream>

DoubleStream

flatMapToDouble (Function mapper)

스트림 <-> 병렬 스트림

Stream<T>

IntStream

LongStream

DoubleStream

Stream<T>

IntStream

LongStream

DoubleStream

parallel() // 스트림->병렬 스트림

sequential() // 병렬 스트림 -> 스트림

스트림 -> 컬렉션

Stream<T>

IntStream

LongStream

DoubleStream

Collection<T>

collect (Collectors.toCollection (Supplier factory))

List<T>

collect (Collectors.toList())

Set<T>

collect (Collectors.toSet())

컬렉션 -> 스트림

Collection<T>, List<T>, Set<T>

Stream<T>

stream()

스트림 -> Map

Stream<T>

IntStream

LongStream

DoubleStream

Map<K,V>

collect(Collectors.toMap(Function key, Function value))

collect(Collectors.toMap(Function key, Function value, BinaryOperator merge))

collect(Collectors.toMap(Function key, Function value, BinaryOperator merge, Supplier mapSupplier))

스트림 -> 배열

Stream<T>

Object[]

toArray()

T[]

toArray(IntFunction<A[]> generator)

IntStream

LongStream

DoubleStream

int[]

long[]

double[]

toArray()



6) Optional<T>과 OptionalInt

- Optional<T>: 'T'타입 객체의 래퍼(Wrapper)클래스

- Optional객체의 값 가져오기

get(): Optional 객체에 저장된 값 반환 // null이면 예외발생

orElse(""): Optional 객체에 저장된 값이 null 일 때 "" 반환

orElseGet(String::new): 람다식 사용가능 () -> new String()

orElseThrow(NullPointerException::new): null일 때 예외 발생

- isPresent(): if(Optional객체의 값==null) return false; else return true;

- 기본형 값을 감싸는 래퍼클래스: OptionalInt, OptionalLong, OptionalDouble

getAs타입() 으로 값을 얻음 // ex) getAsInt()


7) 스트림의 최종연산

- 모든 요소에 지정작업 수행

forEach(Consumer<? super T> action): 병렬스트림인 경우 순서 미보장

forEachOrdered(Consumer<? super T> action): 병렬스트림인 경우에도 순서 보장


- 스트림을 배열로 변환

toArray(): 스트림의 모든 요소를 Object배열에 담아 반환

toArray(IntFunction<A[]> generator) : 스트림의 모든 요소를 A타입의 배열에 담아 반환


- 조건검사

allMatch(Predicate<? super T> predicate): 모든 요소가 조건을 만족시키면 true

anyMatch(Predicate<? super T> predicate): 한 요소라도 조건을 만족시키면 true

noneMatch(Predicate<? super T> predicate): 모든요소가 조건을 만족시키지 않으면 true


- 조건 일치 요소 탐색

findFirst(): 첫 번째 요소를 반환(순차 스트림에서 사용)

findAny(): 아무 요소나 하나를 반환(병렬 스트림에서 사용)


- 스트림에 대한 통계정보 제공: count(), sum(), average(), max(), min()

- 요소를 하나씩 줄여가며 누적연산 수행: reduce() // 초기값, 작업(주로 람다식) 필요


8) collect(), Collector, Collectors

- collect()는 Collector를 매개변수로 하는 스트림의 최종 연산

- 그룹별 reduce() 이용이 가능

- Collector는 수집에 필요한 메소드를 정의해놓은 인터페이스

- Collector 인터페이스

supplier() : 결과 누적할 곳 // 반환 타입: Suppier<A>

accumulator() : 누적 방법 // 반환 타입: BiCounsumer<A, T>

combiner() : 결합 방법(병렬) // 반환 타입: BinaryOperator<A>

finisher() : 최종 변환 // 반환 타입: Function<A, R>

characteristics() : 컬렉터의 특성이 담긴 Set을 반환 // 반환 타입: Set<Characteristics>

- Collectors클래스는 다양한 기능의 컬렉터를 제공

변환: mapping(), toList(), toSet(), toMap(), toCollection() 등

통계: counting(), summingInt(), averagingInt(), maxBy(), minBy(), summarizingInt() 등

문자열 결합: joining()

리듀싱: reducing()

그룹화와 분할: groupingBy(), partitioningBy(), collectingAndThen()


9) Collectors의 메소드

- 스트림을 컬렉션으로 변환: toList(), toSet(), toMap(), toCollection()

- 스트림의 통계정보 제공: counting(), summingInt(), maxBy(), minBy() 등

- 스트림 리듀싱: reducing()

- 문자열 스트림의 요소를 모두 연결: joining()

- 스트림의 요소를 이등분: partitioningBy()

- 스트림의 요소를 그룹화: groupingBy()