mm Home

Java 8 - Stream 본문

개발/Java

Java 8 - Stream

jess_m 2017. 8. 11. 12:00


스트림 API이란?

연속적인 데이터 항목들의 모임들을 처리하는 API 라고 생각한다.

연속적인 데이터를 생성하여, 사용자에 맞는 중간 연산과, 종료연산을 통해 원하는 결과를 추출하도록 도와준다.



가볍게 구조를 나누어보면 이렇게 나눌 수 있다.

- Stream 생성

- 중간 연산 (Intermediate Operations)

- 종료 연산 (Terminal Operations)


구조별로 살펴보자.





스트림 생성

스트림을 생성하는 방법은 여러가지 있다. 연속적인 데이터를 어떻게 Stream의 인터페이스로 생성하느냐의 문제이다. (parallelStream 은 나중에)


Array to Stream



Collection to Stream



Using Stream.generate



Using Stream.iterate

 


Using other Apis

 


이외에도 primitive Stream, File Stream 등 을 지원한다. 자바 문서 참고.





중간 연산(Intermediate Operations)

스트림을 생성해 보았으니, 데이터의 중간 연산작업을 해보자.

중간 연산의 결과는 스트림으로 반환된다. 

중간 연산은 Lazy 연산이기 때문에 자체로는 실행이 되지 않는다. Terminal이 없기 때문이다. (Short Circuit 메소드는 조건이 충족되는대로 종료시키는게 성능상 최선이다. 때문에 Lazy 연산을 통해 사용자가 요청한 이외의 불필요한 작업을 하지 않는 것. 자세히는 다음 장에서 설명하겠다) 아래의 내용에는 결과 표현을 위해 Terminal 연산을 추가하였다. 


map

데이터를 변환하는 매핑 작업이다. 함수(Function)를 적용(apply)함에 따라 인풋 타입에서 리턴 타입으로 변환이 이루어 스트림 요소로 반환한다.


.map()을 통한 연산은 결과를 반환하지 못하므로, forEach를 이용해 프린트를 하였다. 전달받은 String을 upperCase로 변형하는 간단한 작업을 람다 표현식으로 작성하였다.


filter

데이터를 조건(Predicate)에 따라 필터링하는 작업이다.



sorted

comparable이 가능한 객체일 경우 comparator 구현없이 자연적인 분류가 가능한 작업이다. Comparator 를 구현하여 넣어준다면 custom 하게 분류할 수 있다.





종료 연산 (Terminal Operations)

스트림 연산의 조건과 일치하는 요소를 찾기위한 종료연산 작업이다. 스트림 작업의 끝이다. 종료 연산의 결과는 비 스트림 객체를 반환하기 때문에 다시 스트림 연산을 하지 못한다.



조건부 매칭

작업 과정에 일치하는 요소가 있다면 모든 요소를 조회하지 않고 바로 반환하기 때문에 Short Circuit 메소드라고 지칭한다


anyMatch

주어진 조건(Predicate)과 일치하는 요소의 여부(boolean)를 반환한다.  (성격이 비슷한 메소드 allMatch(), noneMatch()도 문서로 알아보라.)



Reduce

전체 요소를 순차적으로 조회하여 단일 요소를 출력하는 형태의 함수. 결과 전체 스트림이 단일 값으로 줄어든다. 

 



Optional

조건에 일치한 요소가 존재하지 않을 때, null을 반환하게 된다. 이러한 경우 Null 체크를 해야한다. 의도치 않은 경우에 오류가 발생하기 쉽다. Java 8에 Optional 클래스가 새로 나왔다. 오브젝트를 담는 컨테이너 클래스라고 보면 될것 같다. 생성된 optional 오브젝트안에 해당 모델 오브젝트를 담고 있다. 자세한 내용은 다음에 작성하겠다.





Collect

중간 연산을 통해 나온 요소들을 수집기(Collectors) 인터페이스에 맞추어 집계하는 메소드이다. 기본적으로 자바에서 지원하는 기본 메소드로 사용이 가능하다. 


toList

모든 스트림 요소들을 ArrayList 타입으로 수집한다. 


toSet

모든 스트림 요소를 HashSet 타입으로 수집한다.


toCollection

위의 형태로 수집할때, 특정 형태의 List 구현체, set 구현체로 수집할 수 없다. (예 LinkedList)

Collection 특정 구현체로 수집을 원한다면 toCollection을 사용하면 된다.


toMap

스트림 요소를 HashMap 형태로 수집을 원하는 경우는 두 기능을 구현해야 한다.

 keyMapper: 스트림 요소에서 Map 형태의 key 추출에 사용

 valueMapper : 스트림 요소에서 Map 형태의 value 추출에 사용

Function.identity()는 항상 input의 인자를 반환하는 함수이다. (인자를 그대로 반환하는 함수. t -> t; )

Hash 특성상 HashKey 가 충돌할 가능성이 있다. 이 경우 충돌을 처리하기 위하여 처리할 함수(BinaryOperator) 지정이 가능하다. 예제로 두 충돌 값 중 첫번째 값을 선택하도록 했다.


groupingBy

스트림 요소를 특정 속성별로 그룹화하고 결과를 Map 형태로 반환한다.


Collectors 에 내장된 counting, summarizing, averaging, max, min, partitioningBy 등 은 자바 문서를 살펴보기 바란다. 


마지막으로 Custom Collector를 구현하고자 한다면, Collector<T, A, R> 인터페이스를 구현하고 Generic 타입을 지정하면 된다.

T : 컬렉션에 사용할 타입

A : 변경 가능한(mutable) 축적 타입

R : 최종 반환될 타입


suppler : combiner에 의해 채워질 새로운 accumulator (누적 계산기) 를 생성하는 메소드. 

accumulator : 누적 결과에 새로운 요소가 추가되는 메소드. (ex. List의 add method)

combiner : 두 accumulator와 병합하는 메소드. (ex. (left, right) -> left.addAll(right.build()); )

finisher : accumulator를 결과 Type으로 변경하는 메소드.

characteristics : 내부 최적화에 사용되는 추가적인 정보를 제공하는 메소드. (자세한건 javaDoc)




'개발 > Java' 카테고리의 다른 글

Java 9 features  (0) 2017.11.10
Java - static  (0) 2017.09.06
Java 8 - Lambda Translation  (0) 2017.08.10
Java 8 - 람다 표현식  (2) 2017.08.10
Java 8 - 동작 파라미터화  (0) 2017.08.10
Comments