CHAP04 - Modern-Java-in-Action/Online-Study GitHub Wiki
-
SELECT name FROM dishes WHERE calorie < 400
- SQLμ§μ μΈμ΄μμλ μ°λ¦¬κ° κΈ°λνλ κ²μ΄ 무μμΈμ§ μ§μ ννν μ μλ€.
- 컬λ μ μΌλ‘λ μ΄μ λΉμ·ν κΈ°λ₯μ λ§λ€ μ μμ§ μμκΉ?
-
λ§μ μμλ₯Ό ν¬ν¨νλ 컀λ€λ 컬λ μ
μ μ΄λ»κ² μ²λ¦¬ν΄μΌ ν κΉ?
- μ±λ₯μ λμ΄λ €λ©΄ λ©ν°μ½μ΄ μν€ν μ²λ₯Ό νμ©ν΄μ λ³λ ¬λ‘ 컬λ μ μ μμλ₯Ό μ²λ¦¬ν΄μΌνλ€.
- νμ§λ§ λ³λ ¬ μ²λ¦¬ μ½λλ₯Ό ꡬννλ κ²μ λ¨μ λ°λ³΅ μ²λ¦¬ μ½λμ λΉν΄ 볡μ‘νκ³ μ΄λ ΅λ€.
- κ²λ€κ° 볡μ‘ν μ½λλ λλ²κΉ λ μ΄λ ΅λ€.
- π μ€νΈλ¦Όμ μ΄μ©νλ©΄
- μ μΈν(μ¦ , λ°μ΄ν°λ₯Ό μ²λ¦¬νλ μμ ꡬν μ½λ λμ μ§μλ‘ ννν μ μλ€.)μΌλ‘ 컬λ μ λ°μ΄ν°λ₯Ό μ²λ¦¬ν μ μλ€.
- λ©ν° μ€λ λ μ½λλ₯Ό ꡬννμ§ μμλ λ°μ΄ν°λ₯Ό ν¬λͺ νκ² λ³λ ¬λ‘ μ²λ¦¬ν μ μλ€. (7μ₯μμ μμΈν)
μμ (filter , sort , λ°ν)
- μ μΉΌλ‘리μ μ리λͺ μ λ°ννκ³ , μΉΌλ‘리λ₯Ό κΈ°μ€μΌλ‘ μ리λ₯Ό μ λ ¬νλ€.
μλ° 7
List<Dish> lowCaloricDishes = new ArrayList<>();
for(Dish dish : menu){
if(dish.getCalories() < 400){
lowCaloricDishes.add(dish);
}
}
Collections.sort(lowCaloricDishes , new Comparator<Dish>(){ // μ΅λͺ
ν΄λμ€λ‘ μ λ ¬
public int compare(Dish dish1 , Dish dish2){
return Integer.compare(dish1.getCalories() , dish2.getCalories());
}
});
List<String> lowCaloricDishesName = new ArrayList<>();
for(Dish dish : lowCaloricDishes){
lowCaloricDishesName.add(dish.getName());
}
-
lowCaloricDishes
λ 컨ν μ΄λ μν λ§ νλ μ€κ° λ³μλ€. (κ°λΉμ§ λ³μ) - μλ° 8 μμ μ΄λ¬ν μΈλΆ ꡬνμ λΌμ΄λΈλ¬λ¦¬ λ΄μμ λͺ¨λ μ²λ¦¬νλ€.
μλ° 8
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
List<String> lowCaloricDishesName =
menu.stream()
.filter(dish -> dish.getCalories() < 400)
.sorted(comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList());
List<String> lowCaloricDishesName =
menu.parallelStream() // λ³λ ¬ μ€ν
.filter(dish -> dish.getCalories() < 400)
.sorted(comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList());
- 7μ₯μμ μλμ νλͺ©μ λν΄ μ€λͺ νλ€.
parallelStream()
μ νΈμΆνμ λ μ νν μ΄λ€ μΌμ΄ μΌμ΄λ κΉ?- μΌλ§λ λ§μ μ€λ λκ° μ¬μ©λλ κ±ΈκΉ?
- μΌλ§λ μ±λ₯μ΄ μ’μκΉ?
- μ μΈνμΌλ‘ μ½λλ₯Ό ꡬννμ¬ λ³νλ μꡬμ¬νμ μ½κ² λμν μ μλ€.
-
filter
,sorted
,map
,collect
κ°μ μ¬λ¬ λΉλ© λΈλ‘ μ°μ°μ μ°κ²°ν΄μ 볡μ‘ν λ°μ΄ν° μ²λ¦¬ νμ΄νλΌμΈμ λ§λ€ μ μλ€.- μμ 4κ°μ§ μ°μ°μ κ³ μμ€ λΉλ© λΈλ‘μΌλ‘ μ΄λ£¨μ΄μ Έ μμΌλ―λ‘ νΉμ μ€λ λ© λͺ¨λΈμ μ νλμ§ μκ³ μμ λ‘κ² μ΄λ€ μν©μμλ μ¬μ©ν μ μλ€.
- π κ²°κ³Όμ μΌλ‘ λ°μ΄ν° μ²λ¦¬ κ³Όμ μ λ³λ ¬ννλ©΄μ μ€λ λμ λ½μ κ±±μ ν νμκ° μλ€.
β 6μ₯ μ€νΈλ¦ΌμΌλ‘ λ°μ΄ν° μμ§
μμ λ§λ³΄κΈ°
Map<Dish.Type , List<Dish>> dishesByType
= menu.stream().collect(groupingBy(Dish::getType));
FISH = [prawns , salmon]
OTHER = [french fries , rice , season fruit , pizza]
MEAT = [pork , beef , chicken]
κΈ°ν λΌμ΄λΈλ¬λ¦¬ : ꡬμλ° , μνμΉ , λλ€μ μ΄
- μλ° νλ‘κ·Έλλ¨Έκ° μ»¬λ μ μ μ μ΄νλ λ° λμμ΄ λλ λ€μν λΌμ΄λΈλ¬λ¦¬κ° μλ€.
- κ΅¬κΈ β ꡬμλ°(Guava) λ λ©ν°λ§΅ , λ©ν°μ λ± μΆκ°μ μΈ μ»¨ν μ΄λ ν΄λμ€λ₯Ό μ 곡νλ€.
- μνμΉ κ³΅ν΅ μ»¬λ μ λΌμ΄λΈλ¬λ¦¬λ μμ λΉμ·ν κΈ°λ₯μ μ 곡νλ€.
- λλ€μ μ΄λ ν¨μν νλ‘κ·Έλλ°μμ μκ°μ λ°μ μ μΈνμΌλ‘ 컬λ μ μ μ μ΄νλ λ€μν μ νΈλ¦¬ν°λ₯Ό μ 곡νλ€.
List<Dish> menu = Arrays.asList(...)
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 , 300 , Dish.Type.FISH),
new Dish("salmon" , false , 450 , Dish.Type.FISH)
);
public Class Dish{..}
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}
}
μ€νΈλ¦Όμ΄λ , λ°μ΄ν° μ²λ¦¬ μ°μ°μ μ§μνλλ‘ μμ€μμ μΆμΆλ μ°μλ μμ
λ‘ μ μν μ μλ€.
- μλ° 8 컬λ μ
μλ μ€νΈλ¦Όμ λ°ννλ
stream
λ©μλκ° μΆκ°λλ€. - μ€νΈλ¦Όμ μΈν°νμ΄μ€ μ μλ
java.util.stream.Stream
μ°Έκ³
-
μ°μλ μμ
- 컬λ μ κ³Ό λ§μ°¬κ°μ§λ‘ μ€νΈλ¦Όμ νΉμ μμ νμμΌλ‘ μ΄λ£¨μ΄μ§ μ°μλ κ° μ§ν©μ μΈν°νμ΄μ€λ₯Ό μ 곡νλ€.
- 컬λ μ μ μ£Όμ λ λ°μ΄ν°μ΄κ³ , μ€νΈλ¦Όμ μ£Όμ λ κ³μ°μ΄λ€.
-
μμ€
- μ€νΈλ¦Όμ 컬λ μ , λ°°μ΄ , I/O μμλ±μ λ°μ΄ν° μ 곡 μμ€λ‘λΆν° λ°μ΄ν°λ₯Ό μλΉνλ€.
- 리μ€νΈλ‘ μ€νΈλ¦Όμ λ§λ€λ©΄ μ€νΈλ¦Όμ μμλ 리μ€νΈμ μμμ κ°μ μμλ₯Ό μ μ§νλ€.
-
λ°μ΄ν° μ²λ¦¬ μ°μ°
- μ€νΈλ¦Όμ ν¨μν νλ‘κ·Έλλ° μΈμ΄μμ μΌλ°μ μΌλ‘ μ§μνλ μ°μ°κ³Ό λ°μ΄ν°λ² μ΄μ€μ λΉμ·ν μ°μ°μ μ§μνλ€.
- μ€νΈλ¦Ό μ°μ°μ μμ°¨μ μΌλ‘ λλ λ³λ ¬λ‘ μ€νν μ μλ€.
-
νμ΄νλΌμ΄λ
- λλΆλΆμ μ€νΈλ¦Ό μ°μ°μ μ€νΈλ¦Ό μ°μ°λΌλ¦¬ μ°κ²°ν΄μ 컀λ€λ νμ΄νλΌμΈμ ꡬμ±ν μ μλλ‘ μ€νΈλ¦Ό μμ μ λ°ννλ€.
- κ·Έ λλΆμ laziness , short-circuitingκ°μ μ΅μ νλ μ»μ μ μλ€. (5μ₯μμ μ€λͺ )
- μ°μ° νμ΄νλΌμΈμ λ°μ΄ν° μμ€μ μ μ©νλ λ°μ΄ν°λ² μ΄μ€ μ§μμ λΉμ·νλ€.
-
λ΄λΆ λ°λ³΅
- λ°λ³΅μλ₯Ό μ΄μ©ν΄μ λͺ μμ μΌλ‘ λ°λ³΅νλ 컬λ μ κ³Ό λ¬λ¦¬ μ€νΈλ¦Όμ λ΄λΆ λ°λ³΅μ μ§μνλ€. (4.3.2μ μμ μ€λͺ )
List<String> threeHighCaloricDishNames =
menu.stream()
.filter(dish -> dish.getCalories() > 300)
.map(Dish::getName)
.limit(3)
.collect(toList());
System.out.println(threeHighCaloricDishNames);
// [pork, beef, chicken]
- menuμ
stream()
λ©μλλ₯Ό νΈμΆν΄μ μ€νΈλ¦Όμ μ»μλ€.- λ°μ΄ν° μμ€λ μ리 리μ€νΈλ€.
- μ리 리μ€νΈλ μ°μλ μμλ₯Ό μ€νΈλ¦Όμ μ 곡νλ€.
- λ€μμΌλ‘ μ€νΈλ¦Όμ
filter
,map
,limit
λ‘ μ΄μ΄μ§λ μΌλ ¨μ λ°μ΄ν° μ²λ¦¬ μ°μ°μ μ μ©νλ€.- π
collect
λ₯Ό μ μΈν λͺ¨λ μ°μ°μ μλ‘ νμ΄νλΌμΈμ νμ±ν μ μλλ‘ μ€νΈλ¦Όμ λ°ννλ€. - νμ΄νλΌμΈμ μμ€μ μ μ©νλ μ§μ κ°μ μ‘΄μ¬λ€.
- π
- λ§μ§λ§μΌλ‘
collect
μ°μ°μΌλ‘ νμ΄νλΌμΈμ μ²λ¦¬ν΄μ κ²°κ³Όλ₯Ό λ°ννλ€.- λ§μ§λ§μ
collect
λ₯Ό νΈμΆνκΈ° μ κΉμ§λ menuμμ 무μλ μ νλμ§ μμΌλ©° μΆλ ₯ κ²°κ³Όλ μλ€. - β μ’
λ£ν μ€νΌλ μ΄ν° μ 무 , μ’
λ£ν μ€νΌλ μ΄ν°λ μμ§λ§ μΈμ€ν΄μ€κ° μ¬μ©λ λ
- νμν λλ§ κ°μ κ³μ°νλ€.
- λ§μ§λ§μ
- λ°μ΄ν°λ₯Ό μΈμ κ³μ°νλλκ° μ»¬λ μ κ³Ό μ€νΈλ¦Όμ κ°μ₯ ν° μ°¨μ΄λ€.
-
컬λ μ
μ νμ¬ μλ£κ΅¬μ‘°κ° ν¬ν¨νλ λͺ¨λ κ°μ λ©λͺ¨λ¦¬μ μ μ₯νλ μλ£κ΅¬μ‘°λ€.
- μ¦ , 컬λ μ μ λͺ¨λ μμλ 컬λ μ μ μΆκ°νκΈ° μ μ κ³μ°λμ΄μΌ νλ€.
-
μ€νΈλ¦Όμ μ΄λ‘ μ μΌλ‘ μμ²ν λλ§ μμλ₯Ό κ³μ°νλ κ³ μ λ μλ£κ΅¬μ‘°λ€.
- μ€νΈλ¦Όμ μμλ₯Ό μΆκ°νκ±°λ μ κ±°ν μ μλ€.
- π μ¬μ©μκ° μμ²νλ κ°λ§ μ€νΈλ¦Όμμ μΆμΆνλ€λ κ²μ΄ ν΅μ¬μ΄λ€.
- κ²μΌλ₯΄κ² λ§λ€μ΄μ§λ 컬λ μ κ³Ό κ°λ€.
-
λ°λ³΅μμ λ§μ°¬κ°μ§λ‘ ν λ² νμν μμλ₯Ό λ€μ νμνλ €λ©΄ μ΄κΈ° λ°μ΄ν° μμ€μμ μλ‘μ΄ μ€νΈλ¦Όμ λ§λ€μ΄μΌνλ€.
- μ¦ , νμλ μ€νΈλ¦Όμ μμλ μλΉλλ€.
- 컬λ μ
μ²λΌ λ°λ³΅ μ¬μ©ν μ μλ λ°μ΄ν° μμ€μ¬μΌνλ€. λ°μ΄ν° μμ€κ°
I/O μ±λ
μ΄λΌλ©΄ μμ€λ₯Ό λ°λ³΅ μ¬μ©ν μ μμΌλ―λ‘ μλ‘μ΄ μ€νΈλ¦Όμ λ§λ€ μ μλ€. - μ€νΈλ¦Όμ λ¨ νλ²λ§ μλΉν μ μλ€λ μ μ λͺ μ¬νμ!
Stream<String> threeHighCaloricDishNames =
menu.stream()
.filter(dish -> dish.getCalories() > 300)
.map(dish -> dish.getName())
.limit(3);
System.out.println(threeHighCaloricDishNames);
System.out.println(threeHighCaloricDishNames);
threeHighCaloricDishNames.forEach(System.out::println);
threeHighCaloricDishNames.forEach(System.out::println);
/*
java.util.stream.SliceOps$1@6acbcfc0
java.util.stream.SliceOps$1@6acbcfc0
pork
beef
chicken
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at Main.main(Main.java:34)
*/
-
μΈλΆ λ°λ³΅
- μ¬μ©μκ° μ§μ μμλ₯Ό λ°λ³΅νλ κ² (컬λ μ
μΈν°νμ΄μ€
for-each
λ±) - 컬λ μ λ΄λΆμ μΌλ‘ μ¨κ²¨μ‘λ λ°λ³΅μλ₯Ό μ¬μ©νλ κ²
- μ¦ , λͺ μμ μΌλ‘ 컬λ μ νλͺ©μ νλμ© κ°μ Έμμ μ²λ¦¬νλ€.
- λ³λ ¬μ±μ μ€μ€λ‘ κ΄λ¦¬ν΄μΌνλ€.
- μ¬μ©μκ° μ§μ μμλ₯Ό λ°λ³΅νλ κ² (컬λ μ
μΈν°νμ΄μ€
List<String> names = new ArrayList<>();
for(Dish dish : menu){
names.add(dish.getName());
}
Iterator<Dish> iterator = menu.iterator();
while(iterator.hasNext()){
Dish dish = iterator.next();
names.add(dish.getName());
}
- μ€νΈλ¦Ό λΌμ΄λΈλ¬λ¦¬λ λ΄λΆ λ°λ³΅μ μ¬μ©νλ€.
- λ°λ³΅μ μμμ μ²λ¦¬νκ³ κ²°κ³Ό μ€νΈλ¦Ό κ°μ μ΄λκ°μ μ μ₯ν΄μ£Όλ κ²
- ν¨μμ μ΄λ€ μμ μ μνν μ§λ§ μ§μ νλ©΄ λͺ¨λ κ²μ΄ μμμ μ²λ¦¬λλ€.
- μμ μ ν¬λͺ νκ² λ³λ ¬λ‘ μ²λ¦¬νκ±°λ , λ μ΅μ νλ λ€μν μμλ‘ μ²λ¦¬ν μ μλ€.
List<String> innerIterNames = menu.stream()
.map(dish -> dish.getName())
.collect(toList());
-
java.util.stream.Stream
μΈν°νμ΄μ€λ λ§μ μ°μ°μ μ μνλ€.
- μ°κ²°ν μ μλ μ€νΈλ¦Ό μ°μ°
-
filter
λsorted
κ°μ μ€κ° μ°μ°μ λ€λ₯Έ μ€νΈλ¦Όμ λ°ννλ€. - πμ€κ° μ°μ°μ μ€μν νΉμ§μ μ΅μ’
μ°μ°μ μ€νΈλ¦Ό νμ΄νλΌμΈμ μ€ννκΈ° μ κΉμ§λ μ무 μ°μ°λ μννμ§ μλλ€λ κ² β
lazy
- μ€κ° μ°μ°μ ν©μΉ λ€μμ ν©μ³μ§ μ€κ° μ°μ°μ μ΅μ’ μ°μ°μΌλ‘ ν λ²μ μ²λ¦¬νκΈ° λλ¬Έμ΄λ€.
List<String> threeHighCaloricDishNames =
menu.stream()
.filter(dish -> {
System.out.println("filtering : " + dish.getName());
return dish.getCalories() > 300;
})
.map(dish -> {
System.out.println("mapping : " + dish.getName());
return dish.getName();
})
.limit(3)
.collect(toList());
System.out.println(threeHighCaloricDishNames);
filtering : pork
mapping : pork
filtering : beef
mapping : beef
filtering : chicken
mapping : chicken
[pork, beef, chicken]
lazy
ν νΉμ± λλΆμ λͺ κ°μ§ μ΅μ ν ν¨κ³Όλ₯Ό μ»μ μ μμλ€.
- 300μΉΌλ‘λ¦¬κ° λλ μ리λ μ¬λ¬ κ°μ§λ§ μ€μ§ μ²μ 3κ°λ§ μ νλμλ€.
- μ΄λ
limit
μ°μ° κ·Έλ¦¬κ³ μΌνΈ μν·μ΄λΌ λΆλ¦¬λ κΈ°λ² λλΆμ΄λ€. (5μ₯μμ μ€λͺ )
- μ΄λ
-
filter
μmap
μ μλ‘ λ€λ₯Έ μ°μ°μ΄μ§λ§ 루ν ν¨μ μ μ¬μ©νμ¬ ν κ³Όμ μΌλ‘ λ³ν©λμλ€.
μ°μ° | λ°ν νμ | μ°μ°μ μΈμ | ν¨μ λμ€ν¬λ¦½ν° |
---|---|---|---|
filter | Stream<T> |
Predicate<T> |
T β boolean |
map | Stream<T> |
Function<T , R> |
T β R |
limit | Stream<T> |
||
sorted | Stream<T> |
Comparator<T> |
(T , T) β int |
distinct | Stream<T> |
- μ€νΈλ¦Όμ λ«λ μ°μ°
- μ€νΈλ¦Ό νμ΄νλΌμΈμμ κ²°κ³Όλ₯Ό λμΆνλ€.
- λ³΄ν΅ μ΅μ’ μ°μ°μ μν΄ List , Integer , void λ± μ€νΈλ¦Ό μ΄μΈμ κ²°κ³Όκ° λ°νλλ€.
μ°μ° | λ°ν νμ | λͺ©μ |
---|---|---|
forEach | void |
μ€νΈλ¦Όμ κ° μμλ₯Ό μλΉνλ©΄μ λλ€λ₯Ό μ μ©νλ€. |
count | long |
μ€νΈλ¦Όμ μμκ°μλ₯Ό λ°ννλ€. |
collect | μ€νΈλ¦Όμ 리λμ€ν΄μ 리μ€νΈ , λ§΅ , μ μ νμμ 컬λ μ μ λ§λ λ€. 6μ₯ μ°Έμ‘° |
- λ€μ μ€νΈλ¦Ό νμ΄νλΌμΈμμ μ€κ° μ°μ°κ³Ό μ΅μ’ μ°μ°μ ꡬλ³νμμ€.
long count = menu.stream()
.filter(d -> d.getCalories() > 300)
.distinct()
.limit(3)
.count();
-
count
λ μ€νΈλ¦Όμ΄ μλlong
μ λ°ννλ€. - λ°λΌμ
count
λ μ΅μ’ μ°μ°μ΄λ€. -
filter
,distinct
,limit
μ μ€νΈλ¦Όμ λ°ννλ©° μλ‘ μ°κ²°ν μ μμΌλ , μ€κ° μ°μ°μ΄λ€.
- μ€νΈλ¦Ό μ΄μ© κ³Όμ μ λ€μκ³Ό κ°μ΄ μΈκ°μ§λ‘ μμ½ν μ μλ€.
- μ§μλ₯Ό μνν (컬λ μ κ°μ) λ°μ΄ν° μμ€
- μ€νΈλ¦Ό νμ΄νλΌμΈμ ꡬμ±ν μ€κ° μ°μ° μ°κ²°
- μ€νΈλ¦Ό νμ΄νλΌμΈμ μ€ννκ³ κ²°κ³Όλ₯Ό λ§λ€ μ΅μ’ μ°μ°
- μ€νΈλ¦Ό νμ΄νλΌμΈμ κ°λ
μ λΉλ ν¨ν΄κ³Ό λΉμ·νλ€.
- λΉλ ν¨ν΄μμλ νΈμΆμ μ°κ²°ν΄μ μ€μ μ λ§λ λ€.
- μ€νΈλ¦Όμμ μ€κ° μ°μ°μ μ°κ²°νλ κ²κ³Ό κ°λ€.
- κ·Έλ¦¬κ³ μ€λΉλ μ€μ μ
build
λ©μλλ₯Ό νΈμΆνλ€- μ€νΈλ¦Όμμ μ΅μ’ μ°μ°κ³Ό κ°λ€.
- λΉλ ν¨ν΄μμλ νΈμΆμ μ°κ²°ν΄μ μ€μ μ λ§λ λ€.
- μ€νΈλ¦Όμ μμ€μμ μΆμΆλ μ°μ μμλ‘ , λ°μ΄ν° μ²λ¦¬ μ°μ°μ μ§μνλ€.
- μ€νΈλ¦Όμ λ΄λΆ λ°λ³΅μ μ§μνλ€.
- μ€νΈλ¦Όμλ μ€κ° μ°μ°κ³Ό μ΅μ’ μ°μ°μ΄ μλ€.
- μ€κ° μ°μ°μ
stream
μ λ°ννλ κ²μ΄λ©° , μ€κ° μ°μ°μΌλ‘λ μ΄λ€ κ²°κ³Όλ μμ±ν μ μλ€. - μ΅μ’
μ°μ°μ
forEach
λcount
μ²λΌstream
μ λ°ννμ§ μλ κ²μ΄λ€. - μ€νΈλ¦Όμ μμλ μμ²ν λ
lazy
νκ² κ³μ°λλ€.