chapter 4. Introducing streams
4.1 What are Streams
- 마치 SQL 쿼리 같이 데이터를 처리
- 많은 요소를 포함하는 커다란 컬렉션을 단순히 처리
Before(Java 7)
List<Dish> lowCaloricDishes = new ArrayList<>();  
for(Dish d: menu){  
  if(d.getCalories() < 400){
    lowCaloricDishes.add(d);
  }
}
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {  
  @Override
  public int compare(Dish d1, Dish d2) {
    return Integer.compare(d1.getCalories(), d2.getCalories());
  }
});
List<String> lowCaloricDishesName = new ArrayList<>();  
for(Dish d: lowCaloricDishes){  
  lowCaloricDishesName.add(d.getName());
}
자바8 코드
List<String> lowCaloricDishesName =  
  menu.stream()
  //menu.parallelStream()
  .filter(d -> d.getCalories() < 400)
  .sorted(Comparator.comparing(Dish::getCalories))
  .map(Dish::getName)
  .collect(toList());
4.2 Getting started with streams
- Sequence of elements - Collections are about data 
- streams are about computations 
 
- Source- 정렬된 컬렉션으로 스트림을 생성하면 정렬이 그대로 유지된다. 즉 리스트로 스트림을 만들면 스크림의 요소는 리스트의 요소와 같은 순서를 유지한다.
 
- Data processing operations- 함수형 프로그래밍 언어에서 일반적으로 지원하는 연산과 데이터베이스와 비슷한 연산을 지원
- 예) filter, map, reduce, find, match, sort 등
- 스트림연산은 순차적으로 또는 병렬로 실행될 수 있다.
 
In addition
- Pipelining- 스트림 연산 끼리 연결하여 커다란 파이프라인을 구성 할 수 있음.
- 게으름(laziness), 쇼트서킷(sort-cicuiting) 같은 최적화를 얻을 수 있음.
- 데이터베이스의 SQL 쿼리 와 비슷
 
- Internal iteration- 반복자를 이용해서 명시적으로 반복하는 컬렉션과 달리 스트림은 내부 반복을 지원
 
List<String> threeHightCaloricDishNames =  
            menu.stream()
            .filter(d -> d.getCalories() > 300)
            .map(Dish::getName)
            .limit(3)
            .collect(toList());
- filter - 람다를 인수로 받아 스트림에서 특정 요소를 제외
 - filter(d -> d.getCalories() > 300) 
- map - 람다를 이용해서 한 요소를 다른 요소로 변환하거나 정보를 추출
 - map(Dish::getName) 
- limit - 정해진 개수 이상을 추출 못하게 한계를 지정
 - limit(3) 
- collect - 스트림을 다른 형식으로 변환
 - collect(toList()); 
4.3 Streams vs. Collections
- DVD vs. Internet stream
- 모든 값을 메모리에 저장하여 계산 vs. 필요할때만 요소를 계산
- 브라우저 인터넷 검색 
- Traversavle only once 
  List<String> title = Arrays.asList("java8", "In", "Action");
      Stream<String> s = title.stream();
      s.forEach(System.out::println);
      s.forEach(System.out::println);
  output :
  java8
  Exception in thread "main" In
  Action
  java.lang.IllegalStateException: stream has already been operated upon or closed
      at java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:274)
      at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
      at Solution.IllegalStateException(Solution.java:77)
      at Solution.main(Solution.java:102)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:497)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
- External vs. internal iteration - for-each loop 
  List<String> names = new ArrayList<>();
  for(Dish d: menu){
    names.add(d.getName());
  }
iterator
  List<String> names = new ArrayList<>();
  Iterator<String> iterator = menu.iterator();
  while(iterator.hasNext()){
    Dish d = iterator.next();
    names.add(d.getName());
  }
stream: internal iteration
  List<String> names = menu.stream()
                           .map(Dish::getName)
                           .collct(toList());

4.4 Stream operations
- intermediate operations 
- terminal operations -  

- Intermediate operations - 다른 intermediate operations 와의 상호연동을 통하여 pipe line 을 형성한다.
- intermediate operations의 동작들이 하나의 terminal operations으로 모이기 때문에 terminal operations이 호출되어서 파이프라인이 시작하기전 까지의 흐름이 동작하지 않는다( lazy)
- 파이프라인이 어떻게 동작되고 있는지 확인하기 위하여 각각의 람다함수에 print 문을 삽입한다.(이러한 코딩은 흔히 사용되지 않지만 배우는 과정이기 때문에 특별한 경우이다.)
 
  List<String> names =
              menu.stream()
              .filter(d -> {
                System.out.println("filtering " + d.getName());
                return d.getCalories() > 300;
              })
              .map(d -> {
                System.out.println("mapping " + d.getName());
                return d.getName();
              })
              .limit(3)
              .collect(toList());
      System.out.println(names);
  filtering pork
  mapping pork
  filtering beef
  mapping beef
  filtering chicken
  mapping chicken
  [pork, beef, chicken]
- 칼로리가 300보다 큰 dish 중에 오직 3개만 추출하고 동작이 끝난다.(Short-circuitinge)
- filter 와 map 의 명령이 하나의 경로로 합쳐져서 동작한다.(loop fusion) - Terminal operations
 
- Stream pipe 로의 결과를 처리한다. 
- List 나 Integer, 혹은 void 등의 스트림이 아닌 다양한 포맷으로 데이터를 변환하여 리턴한다. - menu.stream().forEach(System.out::println); - Working with streams
 
- Builder pattern 과 비슷 
- intermediate operations- filter
- map
- limit
- sorted
- distinct
 
- Terminal operations- forEach
- count
- collect
 
Summary
- stream은 데이터처리동작을 지원하는 source에서 연속된 요소이다.
- Stream은 내부반복을 사용한다.
- intermediate 와 terminal operations 이 있다.
- intermediate operations 은 filter와 map 등 stream을 반환하고 다른 stream와 연동된다. 파이프라인이 설정될뿐 어떤 result 동작을 하지 않는다.
- forEach 와 같은 terminal operations 은 스트림이 아닌 결과를 리턴한다.
- 스트림의 요소는 요청시에 계산된다. 











