Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions modern_java_in_action/mordern-java-in-action-practice/ch4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Chapter 4. 스트림 소개
## 스트림이란 무엇인가요?


## 스트림을 사용하면 어떤 점이 좋은가요?




------------------------------------------



## 4.1 스트림이란 무엇인가요?
- 스트림을 이용하면 선언형으로 컬렉션 데이터를 처리할 수 있다. -> 일단 스트림이 데이터 컬렉션 반복을 멋지게 처리하는 기능이라고 생각하자!
- 또한, 스트림을 이용하면 멀티스레드 코드를 구현하지 않아도 데이터를 투명하게 병렬로 처리할 수 있다.

### 스트림의 특징에 따른 장점
#### 1. 선언형 : 더 간결하고 가독성이 좋아진다.
#### 2. 조립할 수 있음 : 유연성이 좋아진다.
- 여러 빌딩 블록 연산(filter, sorted, map, collect 등)을 연결해서 복잡한 데이터 처리 파이프라인을 만들 수 있다.
- 여러 연산을 파이프라인으로 연결해도 여전히 가독성과 명확성이 유지된다.
#### 3. 병렬화 : 성능이 좋아진다.

## 4.2 스트림 시작하기
- 스트림이란 `데이터 처리 연산을 지원하도록 / 소스에서 추출된 / 연속된 요소`로 정의할 수 있다.
#### 1. 연속된 요소
#### 2. 소스
#### 3. 데이터 처리 연산

- 스트림에는 다음과 같은 2가지 중요 특징이 있다.
#### 특징 1. 파이프라이닝
- ㄹㄹ

#### 특징 2. 내부 반복



## 4.3 스트림과 컬렉션


### 4.3.1 딱 한번만 탐색할 수 있다.


### 4.3.2 외부 반복과 내부 반복
- 컬렉션 인터페이스를 사용하면, 사용자가 지겁 요소를 반복해야 하는 `외부 요소`를 사용한다.
- 반면, 스트림 라이브러리는 (반복을 알아서 처리하고 결과 스트림값을 어딘가에 저장해주는) `내부 반복`을 사용한다.
- 함수에 어떤 작업을 수행할지만 지정하면 모든 것이 알아서 처리된다.



## 4.4 스트림 연산
- `java.util.stream.Stream` 인터페이스는 많은 연산을 정의하는데, 크게 2가지로 구분할 수 있다.
- 연결할 수 있는 스트림 연산을 `중간 연산`이라고 하며, 스트림을 닫는 연산을 `최종 연산`이라고 한다.
- 즉, `filter`, `map`, `limit` 는 서로 연결되어 파이프라인을 형성하고, `collect`로 파이프라인을 실행한 다음에 닫는다.

```java
List<String> names = menu.stream() // 요리 리스트에서 스트림 얻기
.filter(dish -> dish.getCalories() > 300) // 중간 연산
.map(Dish::getName) // 중간 연산
.limit(3) // 중간 연산
.collect(toList()); // 스트림을 리스트로 변환
```

### 4.4.1 중간 연산
- 중간 연산은 다른 스트림을 반환한다. 따라서, 여러 중간 연산을 연결해서 질의를 만들 수 있다.
- 중간 연산의 특징은 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다는 것이다.
- 즉 Lazy 하다는 것이다. 중간 연산을 합친 다음에 중간 연산을 최종 연산으로 한 번에 처리하기 때문이다.
- 스트림의 게으른 특성 덕분에 몇가지 최적화 효과를 얻을 수 있었다.
#### 최적화 효과 1. limit 연산 그리고 쇼트 서킷
- 300칼로리가 넘은 요리는 여러 개지만, 오직 처음 3개만 선택되었다.
#### 최적화 효과 2. 루프 퓨전(loop fusion)
- filter와 map은 서로 다른 연산이지만 한 과정으로 병합되었다.


### 4.4.2 최종 연산
- 최종 연산은 스트림 파이프라인에서 결과를 도출한다.
- 보통 최종 연산에 의해 List, Integer, void 등 스트림 이외의 결과가 반환된다.

### 4.4.3 스트림 이용하기
- 스트림 이용 과정은 다음과 같이 3가지로 요약할 수 있다.
1. 질의를 수행할 (컬렉션 같은) `데이터 소스`
2. 스트림 파이프라인을 구성할 `중간 연산` 연결
3. 스트림 파이프라인을 실행하고 결과를 만들 `최종 연산`












Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.example.mordernjavainactionpractice;

import java.util.Arrays;
import java.util.List;

public class Dish {

private final String name;
private final boolean vegetarian;
private final int calories;
private final Type type;

public Dish(String name, boolean vegetarian, int calories, Type type) {
this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}

public String getName() {
return name;
}

public boolean isVegetarian() {
return vegetarian;
}

public int getCalories() {
return calories;
}

public Type getType() {
return type;
}

public enum Type { MEAT, FISH, OTHER }

@Override
public String toString() {
return name;
}

public static final List<Dish> menu =
Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 530, Dish.Type.OTHER),
new Dish("rice", true, 350, Dish.Type.OTHER),
new Dish("season fruit", true, 120, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
new Dish("prawns", false, 400, Dish.Type.FISH),
new Dish("salmon", false, 450, Dish.Type.FISH));
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
package com.example.mordernjavainactionpractice;

import org.springframework.boot.SpringApplication;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

import java.util.List;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ModernJavaInActionPracticeApplication {

public static void main(String[] args) {
SpringApplication.run(ModernJavaInActionPracticeApplication.class, args);
getLowCaloricDishesNamesInJava8(Dish.menu).forEach(System.out::println);
}

// Java 8
public static List<String> getLowCaloricDishesNamesInJava8(List<Dish> dishes) {
return dishes.parallelStream()
.filter(d -> d.getCalories() < 400) // 400 이하의 요리 담기
.sorted(comparing(Dish::getCalories)) // 칼로리 순으로 정렬
.map(Dish::getName) // 요리 이름만 담기
.collect(toList());
}
}