Skip to content

Latest commit

 

History

History
130 lines (91 loc) · 9.96 KB

stream.md

File metadata and controls

130 lines (91 loc) · 9.96 KB

Java의 스트림(stream)

  스트림(stream)은 Java 8 버전부터 람다와 함께 지원되기 시작한 기능이다. 이전까지 Java에서 데이터를 다룰 때 for문과 Iterator를 이용해왔다. 이러한 방식들은 코드 가독성과 재사용성이 떨어지고, 가장 큰 문제점은 데이터 소스마다 다른 방식으로 다뤄야 한다는 것이었다. Iterator 등을 이용해 표준화 했지만, Collections.sort(), Arrays.sort() 등 같은 기능의 중복된 메서드들은 여전히 불편하다. 이를 해결하기 위해 stream이 등장했다.


스트림(stream)

  스트림은 데이터 소스를 추상화하고, 데이터를 다루는데 자주 사용되는 메서드들을 정의 해놓다. 아래 코드와 같이 스트림을 사용하면 코드가 간결해져 이해하기 쉽고, 재사용성 또한 높다.

String[] sArr = {"bbb", "ccc", "aaa"};
List<String> sList = Arrays.asList(sArr);

Stream<String> stream1 = Arrays.stream(sArr);
Stream<String> stream2 = sList.stream();

stream1.sorted.forEach(System.out::println);
stream2.sorted.forEach(System.out::println);

스트림은 데이터 소스를 변경하지 않는다.

→ stream은 데이터 소스로부터 데이터를 읽기만할 뿐, 데이터 소스를 변경하지는 않음

List<String> sList = Arrays.asList({"bbb", "ccc", "aaa"});
Stream<String> stream = sList.stream();

// 정렬 결과를 새로운 List에 담아서 반환
List<String> sortedList = stream.sorted.collect(Collections.toList());

스트림은 일회용이다.

→ stream은 한번 사용하면 닫혀서 다시 사용할 수 없음

List<String> sList = Arrays.asList({"bbb", "ccc", "aaa"});
Stream<String> stream = sList.stream();

stream.sorted.forEach(System.out::println);
int numOfStr = stream.count();  // Error: 스트림이 이미 닫혔음

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

  • 내부 반복: 반복문을 메서드 내부에 숨길 수 있음
  • 스트림을 이용한 작업이 간결할 수 있는 비결
List<String> sList = Arrays.asList({"bbb", "ccc", "aaa"});
for(String s : sList)
    System.out.println(s);

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

스트림의 연산

stream.distinct().limit(5).sorted().forEach(System.out::println);
  • 중간 연산
    • 연산 결과가 스트림인 연산
    • 스트림에 연속해서 중간 연산할 수 있음
    • 위 예제의 distinct(), limit(), sorted()
  • 최종 연산
    • 연산 결과가 스트림이 아닌 연산
    • 스트림의 요소를 소모하므로 단 한번만 가능
    • forEach()
중간연산 설명
Stream<T> distinct() 중복 제거
Stream<T> filter(Predicate<T> predicate) 조건에 안 맞는 요소 제외
Stream<T> limit(long maxSize) 스트림의 일부를 잘라냄
Stream<T> skip(Long n) 스트림의 일부를 건너뜀
Stream<T> peek(Consumer<T> action) 스트림의 요소에 작업 수행
Stream<T> sorted()
Stream<T> sorted(Comparator<T> comparator)
스트림의 요소를 정렬
Stream<R> map(Function<T, R> mapper)
DoubleStream mapToDouble(ToDoubleFunction<T> mapper)
IntStream mapToInt(ToIntFunction<T> mapper)
LongStream mapToLong(ToLongFunction<T> mapper)
스트림의 요소를 반환
Stream<R> flatMap(Function<T, Stream<R>> mapper)
DoubleStream flatMapToDouble(Function<T, DoubleStream> mapper)
IntStream flatMapToInt(Function<T, IntStream> mapper)
LongStream flatMapToLong(Function<T, LongStream> mapper)
스트림의 요소를 반환

최종연산 설명
void forEach(Consumer<? Super T> action)
void forEachOrdered(Consumer<? Super T> action)
각 요소에 지정된 작업 수행
long count() 스트림의 요소의 개수 반환
Optional<T> max(Comparator<? super T> comparator)
Optional<T> min(Comparator<? super T> comparator)
스트림의 최대값/최소값 반환
Optional<T> findAny() → 아무거나 하나
Optional<T> findFirst() → 첫 번째 요소
스트림의 요소 하나를 반환
boolean allMatch(Predicate<T> p) → 모두 만족
boolean anyMatch(Predicate<T> p)→ 하나라도 만족
boolean noneMatch(Predicate<> p)→ 모두 만족 X
주어진 조건을 모든 요소가 만족시키는지, 만족시키지 않는지 확인
Object[ ] toArray()
A[ ] toArray(IntFunction<A[ ]> generator)
스트림의 모든 요소를 배열로 반환
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
U reduce(U identity, BiFunction<U, T, U> accumulator, BinaryOperator<U> combiner)
스트림의 요소를 하나씩 줄여가면서 계산
R collect(Collector<T, A, R> collector)
R collect(Supplier<R> supplier, BiConsumer<R, T> accumulator, BiConsumer<R, R> combiner)
스트림의 요소 수집
주로 요소를 그룹화하거나 분할한 결과를 컬렉션에 담아 반환하는 데에 사용

지연된 연산

  • 최종연산이 수행되기 전까지 중간연산이 수행되지 않음
  • 최종연산이 수행돼야 스트림의 요소들이 중간연산을 거쳐 최종연산에서 소모됨

Stream<Integer>와 IntStream

  • 요소의 타입이 T인 스트림 → Stream<T>
  • Autoboxing과 Unboxing으로 인한 비효율을 줄이기 위해 기본형으로 다루는 스트림 제공
    • IntStream, DoubleStream, LongStream
    • 더 효율적

병렬 스트림

  • 스트림의 장점 중 하나 → 병렬 처리가 쉽다
  • 내부적으로 프레임워크를 이용해 자동으로 연산을 병렬 수행
  • 그저 스트림에 parallerl() 메서드를 호출하면 됨

참고자료