본문 바로가기

Java/기초

[Java] 스트림(Stream)

자바 8에서 추가된 스트림(Stream)은 람다를 활용할 수 있는 기술 중 하나이다.

자바 8이전에는 배열, 컬렉션 인스턴스를 다루는 방법은 for 또는 foreach 문을 돌면서 요소 하나씩 꺼내서 다루는 방법이였다. 이 방법식으로 작성된 코드는 너무 길고 알아보기 어렵다. 그리고 재사용성도 떨어진다.

  • 이전 방식들의 문제를 해결하기 위해서
    • 너무 길고 알아보기 어렵다. 그리고 재사용성도 떨어진다.
    • 각 컬렉션 클래스에는 같은 기능의 메서드들이 중복되어 정의되어 있다.

스트림 특징

1. 스트림은 외부 반복을 통해 작업하는 컬렉션과는 달리 내부 반복(internal iteration)을 통해 작업을 수행합니다.

2. 스트림은 재사용이 가능한 컬렉션과는 달리 단 한 번만 사용할 수 있습니다.

3. 스트림은 원본 데이터를 변경하지 않습니다.

4. 스트림의 연산은 필터-맵(filter-map) 기반의 API를 사용하여 지연(lazy) 연산을 통해 성능을 최적화합니다.

5. 스트림은 parallelStream() 메소드를 통한 손쉬운 병렬 처리를 지원합니다. 

스트림의 연산

  • 스트림에 정의된 메서드 중에서 데이터 소스를 다루는 작업을 수행하는 것은 연산(operation)이라고 한다.
String[] strings2 = {"ccc", "bbb", "aaa","ccc","bbb"};
Stream<String> stream = Arrays.stream(strings2);

stream.distinct().sorted().limit(2).forEach(System.out::println);
  • 중간연산
    • 연산 결과가 스트림인 연산
    • 스트림에 연속해서 중간 연산할 수 있음
    • map() : 스트림 요소에 저장된 값 중에서 원하는 필드만 뽑아내거나 특정 형태로 변환
    • flatMap() : Stream<T[]>를 Stream<T>로 변환
      • 스트림의 요소가 배열이거나 map()의 연산결과가 배열일 경우 
  • 최종연산
    • 연산 결과가 스트림이 아닌 연산
    • 스트림의 요소를 소모하므로 단 한번만 가능
    • reduce(), collect()

※ 지연된 연산 : 최종연산이 수행되기 전까지의 중간연산은 수행되지 않는다.

 

Stream 인터페이스의 collect와 reduce 메서드의 차이는 무엇인가?

reduce메서드는 요소를처리할 때 항상 새 값을 생성하지만 , collect메서드는 기존 값을 수정하거나 변경하다.

 

collect 메서드는 도출하려는 결과를 누적하는 컨테이너를 바꾸도록 설계된 메서드인 반면 reduce는 두 값을 하나로 도출하는 불변형 연산이라는 점에서 의미론적인 문제가 일어난다. reduce 메서드는 누적자로 사용된 리스트를 변환시키므로 reduce를 잘못 활용하게 된다.

가변 컨테이너 관련 작업이면서 병렬성을 확보하려면 collect 메서드로 리듀싱 연산을 구현하는 것이 바람직하다.

forEach집계와 향상된 for문 또는 반복자와 다른점은 무엇인가?

  • forEach집계 작업을 통해 시스템은 반복이 발생하는 "방법"을 결정할 수 있다.
  • 집계 연산을 사용하면 "어떻게" 대신 "무엇"에 집중할 수 있다.

집계 연산(Operations)과 반복자(Iterators)의 근본적인 차이점

집계 연산의 경우 다음과 같습니다.

  • 내부 반복을 사용
  • 스트림에서 요소를 처리
  • 매개변수로 동작을 지원

Collector 인터페이스의 groupingBy, partitioningBy의 차이점은 무엇인가?

//groupingBy
Collector groupingBy(Function classifier)
Collector groupingBy(Function classifier, Collector downstream)
Collector groupingBy(Function classifier, Supplier mapFactory, Collector downstream)

//partitioningBy
Collector partitioningBy(Predicate predicate)
Collector partitioningBy(Predicate predicate, Collector downstream)

메서드 정의를 보면 분류를 Function, Predicate로 하느냐의 차이점만 있을 뿐 동일하다.

스트림을 두개의 그룹으로 나눠야 한다면, partitioningBy()로 분할하는 것이 더 빠르다. 그 외에는 groupingBy()를 쓰면 된다.

그룹화와 분한 결과는 Map에 담겨 반환된다.

 

출처 : 

https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html

 

Reduction (The Java™ Tutorials > Collections > Aggregate Operations)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

https://docs.oracle.com/javase/tutorial/collections/streams/index.html

 

Lesson: Aggregate Operations (The Java™ Tutorials > Collections)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

'Java > 기초' 카테고리의 다른 글

[Java] Optional  (0) 2021.08.25
[Java] 입력 뜯어보기(Scanner, InputStream, BufferdReader)  (0) 2021.08.14
[Java] 람다식(Lambda expression)  (0) 2021.08.10
[Java] 쓰레드(Thread) - 2/2 (동기화)  (0) 2021.08.09
[Java] JVM메모리 구조  (0) 2021.08.08