[java8 in action 일부 참고]
한마디로, Collection은 data라고 한다면 Stream은 computation이다.
<특징 2가지>
1. PipeLining
Stream 은 unix명령어인 pipeline( "|" ) 과 같이 순차적으로 data를 처리한다.
(단, 실제로 unix에선 pipeline을 순차적으로 처리하지 않고, 몇줄이라도 조금씩 output이 있으면 동시처리를 한다)
2. Internal iteration
- 코드상 눈에 보이지는 않지만, 내부적으로 iteration이 일어난다.
- 단 한번 traverse가 가능하다. 이게 끝나면 다시 new stream을 가져와야 한다.
<operation 종류> - Builder패턴과 유사하게 chain을 통해 중간단계를 여러개 거쳐 최종물 생성.
1. Intermediate Operation : Terminal Operation을 만나야만 동작을 한다.
- map, filter 등과 같이 중간에 데이타를 가공한다.
- sorted, distinct
- limit, skip
- 한꺼번에 처리가 되는만큼, 내부 동작 순서는 최적화해서 바뀐다.
(예: limit먼저 실행하고 다른 것 들 실행. map과 filter를 merge해서 실행)
2. Terminal Operation : 반드시 이걸로 끝나야 한다. 그래야만 intermediate Operation도 동작을 한다.
- collect (주로 List, Map, an Integer 리턴)
ㅁ Map으로 변경
someList.stream() .collect(Collectors.toMap(AClassName::getMyCode, AClassName::getName))
ㅁ GroupingBy
someList.stream().
.collect(Collectors.groupingBy( AClassName::getName ) )
=> Map<String, List<Person>> 형태로 리턴됨.
ㅁ guava와 함께 쓰면: .collect(GuavaCollectors.toImmutableList());
jp.skypencil.guava:helper:1.0.1
<dependency>
<groupId>jp.skypencil.guava</groupId>
<artifactId>helper</artifactId>
<version>1.0.1</version>
</dependency>
- forEach (void 리턴)
- count ( long 숫자 return)
ofNullable함께 사용: REF
map으로 예제: REF
Function protoype 이용예제: REF
<철학>
java8에서는 stream을 이용해 multicore 개발의 복잡함과, multihread로 인한 오류확률을 줄이고자 한다.
-> stream은 multicore에서도 parallel한 환경에서 transparent하게 작업이 가능하다.
일반적으로, .stream()에서 .parallelStream()으로만 바꾸면, 별도의 multithread코드 없이 parallel작업이 된다.
<forEach 예제>
"hey duke".chars().forEach (c -> System.out.println((char)c)); My-Ref
someStream.forEach ( (oneItem) -> {
oneItem.weight -= 1;
oneItem.height += 10;
}
단, 단순한 forEach는 Collector 에도 있으므로, list.forEach( item -> blabla ); 가 가능함.