Part 2-1 ํจ์ํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
Part 2-1 ํจ์ํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ด๋ จ
4์ฅ - ์คํธ๋ฆผ ์๊ฐ
DB์์๋ select name from dishes where calorie < 400
๋ฌธ์ฅ ์ฒ๋ผ ์ ์ธํ์ผ๋ก ์ฐ์ฐ์ ํํํ ์ ์๋ค(์ง์ ๊ตฌํํ ํ์๊ฐ ์๋ค). SQL ์ง์ ์ธ์ด์์๋ ์ฐ๋ฆฌ๊ฐ ๊ธฐ๋ํ๋ ๊ฒ์ด ๋ฌด์์ธ์ง ์ง์ ํํํ ์ ์๋ค.
์คํธ๋ฆผ์ด๋ ๋ฌด์์ธ๊ฐ?
์คํธ๋ฆผ ์ด๋ ์๋ฐ API์ ์๋ก ์ถ๊ฐ๋ ๊ธฐ๋ฅ์ผ๋ก, ์คํธ๋ฆผ์ ์ด์ฉํ๋ฉด ์ ์ธํ(์ฆ, ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์์ ๊ตฌํ ์ฝ๋ ๋์ ์ง์๋ก ํํํ ์ ์๋ค)์ผ๋ก ์ปฌ๋ ์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค. ๋ํ ์คํธ๋ฆผ์ ์ด์ฉํ๋ฉด ๋ฉํฐ ์ค๋ ๋ ์ฝ๋๋ฅผ ๊ตฌํํ์ง ์์๋ ๋ฐ์ดํฐ๋ฅผ ํฌ๋ช ํ๊ฒ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ ์ ์๋ค. ๋ค์ ์์ ๋ ์ ์นผ๋ก๋ฆฌ์ ์๋ฆฌ๋ช ์ ๋ฐํํ๊ณ , ์นผ๋ก๋ฆฌ๋ฅผ ๊ธฐ์ค์ผ๋ก ์๋ฆฌ๋ฅผ ์ ๋ ฌํ๋ ์๋ฐ7 ์ฝ๋๋ค.
List<Dish> lowCaloricDishes = new ArrayList<>();
for(Dish d : menu){
if(d.getCalories() < 400){
lowCaloricDishes.add(d);
}
}
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
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());
}
์ ์ฝ๋์์๋ lowCaloricDishes
๋ผ๋ โ๊ฐ๋น์ง ๋ณ์โ๊ฐ ์ฌ์ฉ๋์๋ค. ์ฆ lowCaloricDishes
๋ ์ปจํ
์ด๋ ์ญํ ๋ง ํ๋ ์ค๊ฐ ๋ณ์๋ค. ์๋ฐ8์์ ์ด๋ฌํ ์ธ๋ถ ๊ตฌํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด์์ ๋ชจ๋ ์ฒ๋ฆฌํ๋ค.
//์๋ฐ8 ์ฝ๋
import static java.util.Comparator.comparing;
import static java.uitl.stream.Collectors.toList;
List<String> lowCaloricDishesName = menu.stream()
.filter(d -> d.getCalories() < 400) // 400์นผ๋ก๋ฆฌ ์ดํ์ ์๋ฆฌ ์ ํ
.sorted(comparing(Dish::getCalories)) // ์นผ๋ก๋ฆฌ๋ก ์๋ฆฌ ์ ๋ ฌ
.map(Dish::getName) // ์๋ฆฌ๋ฉด ์ถ์ถ
.collect(toList()); // ๋ชจ๋ ์๋ฆฌ๋ช
์ ๋ฆฌ์คํธ์ ์ ์ฅ
stream()
์ parallelStream()
์ผ๋ก ๋ฐ๊พธ๋ฉด ์ด ์ฝ๋๋ฅผ ๋ฉํฐ์ฝ์ด ์ํคํ
์ฒ์์ ๋ณ๋ ฌ๋ก ์คํํ ์ ์๋ค.
List<String> lowCaloricDishesName = menu.parallelStream()
.filter(d -> d.getCalories() < 400) // 400์นผ๋ก๋ฆฌ ์ดํ์ ์๋ฆฌ ์ ํ
.sorted(comparing(Dish::getCalories)) // ์นผ๋ก๋ฆฌ๋ก ์๋ฆฌ ์ ๋ ฌ
.map(Dish::getName) // ์๋ฆฌ๋ฉด ์ถ์ถ
.collect(toList()); // ๋ชจ๋ ์๋ฆฌ๋ช
์ ๋ฆฌ์คํธ์ ์ ์ฅ
์์ธํ ๋ด์ฉ์ 7์ฅ์์ ์ค๋ช ํ๊ฒ ๋ค.
์คํธ๋ฆผ ์์ํ๊ธฐ
์คํธ๋ฆผ์ด๋ ์ ํํ ๋ญ๊น? ์คํธ๋ฆผ์ด๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฐ์ฐ์ ์ง์ํ๋๋ก ์์ค์์ ์ถ์ถ๋ ์ฐ์๋ ์์ ๋ก ์ ์ํ ์ ์๋ค. ์ด ์ ์๋ฅผ ํ๋์ฉ ์ดํด๋ณด์.
์ฐ์๋ ์์ : ์ปฌ๋ ์
๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์คํธ๋ฆผ์ ํน์ ์์ ํ์์ผ๋ก ์ด๋ฃจ์ด์ง ์ฐ์๋ ๊ฐ ์งํฉ์ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค. ์ปฌ๋ ์
์ ์๋ฃ๊ตฌ์กฐ์ด๋ฏ๋ก ์ปฌ๋ ์
์์๋ (์๋ฅผ ๋ค์ด ArrayList
๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ์ง ์๋๋ฉด LinkedList
๋ฅผ ์ฌ์ฉํ ๊ฒ์ด์ง์ ๋ํ) ์๊ฐ๊ณผ ๊ณต๊ฐ์ ๋ณต์ก์ฑ๊ณผ ๊ด๋ จ๋ ์์ ์ ์ฅ ๋ฐ ์ ๊ทผ ์ฐ์ฐ์ด ์ฃผ๋ฅผ ์ด๋ฃฌ๋ค. ๋ฐ๋ฉด ์คํธ๋ฆผ์ filter
, sorted
, map
์ฒ๋ผ ํํ ๊ณ์ฐ์์ด ์ฃผ๋ฅผ ์ด๋ฃฌ๋ค. ์ฆ, ์ปฌ๋ ์
์ ์ฃผ์ ๋ ๋ฐ์ดํฐ๊ณ ์คํธ๋ฆผ์ ์ฃผ์ ๋ ๊ณ์ฐ์ด๋ค.
์์ค : ์คํธ๋ฆผ์ ์ปฌ๋ ์ , ๋ฐฐ์ด, I/O ์์ ๋ฑ์ ๋ฐ์ดํฐ ์ ๊ณต ์์ค๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์๋นํ๋ค. ์ ๋ ฌ๋ ์ปฌ๋ ์ ์ผ๋ก ์คํธ๋ฆผ์ ์์ฑํ๋ฉด ์ ๋ ฌ์ด ๊ทธ๋๋ก ์ ์ง๋๋ค. ์ฆ, ๋ฆฌ์คํธ๋ก ์คํธ๋ฆผ์ ๋ง๋ค๋ฉด ์คํธ๋ฆผ์ ์์๋ ๋ฆฌ์คํธ์ ์์์ ๊ฐ์ ์์๋ฅผ ์ ์งํ๋ค.
๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฐ์ฐ : ์คํธ๋ฆผ์ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ์ผ๋ฐ์ ์ผ๋ก ์ง์ํ๋ ์ฐ์ฐ๊ณผ DB์ ๋น์ทํ ์ฐ์ฐ์ ์ง์ํ๋ค. ์๋ฅผ ๋ค์ด filter
, map
, reduce
, find
, match
, sort
๋ฑ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ ์ ์๋ค.
๋ํ ์คํธ๋ฆผ์ ๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง ์ค์ํ ํน์ง์ ๊ฐ๋๋ค.
ํ์ดํ๋ผ์ด๋ : ์คํธ๋ฆผ ์ฐ์ฐ์ ์คํธ๋ฆผ ์ฐ์ฐ๋ผ๋ฆฌ ์ฐ๊ฒฐํด์ ์ปค๋ค๋ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ ์ ์๋๋ก ์คํธ๋ฆผ์ ์์ ์ ๋ฐํํ๋ค. ๋ด๋ถ ๋ฐ๋ณต : ๋ฐ๋ณต์๋ฅผ ์ด์ฉํด์ ๋ช ์์ ์ผ๋ก ๋ฐ๋ณตํ๋ ์ปฌ๋ ์ ๊ณผ ๋ฌ๋ฆฌ ์คํธ๋ฆผ์ ๋ด๋ถ ๋ฐ๋ณต์ ์ง์ํ๋ค.
import static java.util.stream.Collectors.toList;
List<String> threeHighCaloricDishNames = menu.stream() // ๋ฉ๋ด(์๋ฆฌ ๋ฆฌ์คํธ)์์ ์คํธ๋ฆผ์ ์ป๋๋ค.
.filter(d -> d.getCalories() > 300) // ํ์ดํ๋ผ์ธ ์ฐ์ฐ ๋ง๋ค๊ธฐ. ์ฒซ ๋ฒ์งธ๋ก ๊ณ ์นผ๋ก๋ฆฌ ์๋ฆฌ๋ฅผ ํํฐ๋งํ๋ค.
.map(Dish::getName) // ์๋ฆฌ๋ช
์ถ์ถ
.limit(3) //์ ์ฐฉ์ ์ธ ๊ฐ๋ง ์ ํ
.collect(toList()); // ๊ฒฐ๊ณผ๋ฅผ ๋ค๋ฅธ ๋ฆฌ์คํธ๋ก ์ ์ฅ
System.out.println(threeHighCaloricDishNames);
// ๊ฒฐ๊ณผ๋ [pork, beef, chicken] ์ด๋ค.
์ฐ์ menu
์ stream
๋ฉ์๋๋ฅผ ํธ์ถํด์ ์๋ฆฌ ๋ฆฌ์คํธ(menu)๋ก๋ถํฐ ์คํธ๋ฆผ์ ์ป์๋ค. ์ฌ๊ธฐ์ ๋ฐ์ดํฐ ์์ค๋ ์๋ฆฌ ๋ฆฌ์คํธ(menu
)๋ค. ๋ฐ์ดํฐ ์์ค๋ ์ฐ์๋ ์์๋ฅผ ์คํธ๋ฆผ์ ์ ๊ณตํ๋ค. ๋ค์์ผ๋ก ์คํธ๋ฆผ์ filter
, map
, limit
, collect
๋ก ์ด์ด์ง๋ ์ผ๋ จ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฐ์ฐ์ ์ ์ฉํ๋ค. collect
๋ฅผ ์ ์ธํ ๋ชจ๋ ์ฐ์ฐ์ ์๋ก ํ์ดํ๋ผ์ธ์ ํ์ฑํ ์ ์๋๋ก ์คํธ๋ฆผ์ ๋ฐํํ๋ค. ๋ง์ง๋ง์ผ๋ก collect
์ฐ์ฐ์ผ๋ก ํ์ดํ๋ผ์ธ์ ์ฒ๋ฆฌํด์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ค(collect
๋ ์คํธ๋ฆผ์ด ์๋๋ผ List
๋ฅผ ๋ฐํํ๋ค). ๋ง์ง๋ง์ collect
๋ฅผ ํธ์ถํ๊ธฐ ์ ๊น์ง๋ menu
์์ ์๋ฌด๊ฒ๋ ์ ํ๋์ง ์์ผ๋ฉฐ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ ์๋ค. ์ฆ, collect
๊ฐ ํธ์ถ๋๊ธฐ ์ ๊น์ง ๋ฉ์๋ ํธ์ถ์ด ์ ์ฅ๋๋ ํจ๊ณผ๊ฐ ์๋ค.
์คํธ๋ฆผ๊ณผ ์ปฌ๋ ์
์๋ฐ์ ๊ธฐ์กด ์ปฌ๋ ์ ๊ณผ ์๋ก์ด ์คํธ๋ฆผ ๋ชจ๋ ์ฐ์๋ ์์ ํ์์ ๊ฐ์ ์ ์ฅํ๋ ์๋ฃ๊ตฌ์กฐ์ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค. ์ฌ๊ธฐ์ โ์ฐ์๋โ์ด๋ผ๋ ํํ์ ์์์ ์๊ด์์ด ์๋ฌด ๊ฐ์๋ ์ ์ ํ๋ ๊ฒ์ด ์๋๋ผ ์์ฐจ์ ์ผ๋ก ๊ฐ์ ์ ๊ทผํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค. ์ด์ ์ปฌ๋ ์ ๊ณผ ์คํธ๋ฆผ์ ์ฐจ์ด๋ฅผ ์ดํด๋ณด์.
๋ฐ์ดํฐ๋ฅผ ์ธ์ ๊ณ์ฐํ๋๋๊ฐ ์ปฌ๋ ์ ๊ณผ ์คํธ๋ฆผ์ ๊ฐ์ฅ ํฐ ์ฐจ์ด๋ผ๊ณ ํ ์ ์๋ค. ์ปฌ๋ ์ ์ ํ์ฌ ์๋ฃ๊ตฌ์กฐ๊ฐ ํฌํจํ๋ ๋ชจ๋ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ ์๋ฃ๊ตฌ์กฐ๋ค. ์ฆ, ์ปฌ๋ ์ ์ ๋ชจ๋ ์์๋ ์ปฌ๋ ์ ์ ์ถ๊ฐํ๊ธฐ ์ ์ ๊ณ์ฐ๋์ด์ผ ํ๋ค(์ปฌ๋ ์ ์ ์์๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ปฌ๋ ์ ์ ์์๋ฅผ ์ญ์ ํ ์ ์๋ค. ์ด๋ฐ ์ฐ์ฐ์ ์ํํ ๋๋ง๋ค ์ปฌ๋ ์ ์ ๋ชจ๋ ์์๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํด์ผ ํ๋ฉฐ ์ปฌ๋ ์ ์ ์ถ๊ฐํ๋ ค๋ ์์๋ ๋ฏธ๋ฆฌ ๊ณ์ฐ๋์ด์ผ ํ๋ค).
๋ฐ๋ฉด ์คํธ๋ฆผ์ ์ด๋ก ์ ์ผ๋ก ์์ฒญํ ๋๋ง ์์๋ฅผ ๊ณ์ฐ ํ๋ ๊ณ ์ ๋ ์๋ฃ๊ตฌ์กฐ๋ค(์คํธ๋ฆผ์ ์์๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์คํธ๋ฆผ์์ ์์๋ฅผ ์ ๊ฑฐํ ์ ์๋ค). ์ฌ์ฉ์๊ฐ ์์ฒญํ๋ ๊ฐ๋ง ์คํธ๋ฆผ์์ ์ถ์ถํ๋ค๋ ๊ฒ์ด ํต์ฌ์ด๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์คํธ๋ฆผ์ ์์ฐ์์ ์๋น์ ๊ด๊ณ๋ฅผ ํ์ฑํ๋ค. ๋ํ ์คํธ๋ฆผ์ ๊ฒ์ผ๋ฅด๊ฒ ๋ง๋ค์ด์ง๋ ์ปฌ๋ ์ ๊ณผ ๊ฐ๋ค. ์ฆ, ์ฌ์ฉ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ ๋๋ง ๊ฐ์ ๊ณ์ฐํ๋ค. ๋ฐ๋ฉด ์ปฌ๋ ์ ์ ์ ๊ทน์ ์ผ๋ก ์์ฑ๋๋ค(์์ฐ์ ์ค์ฌ: ํ๊ธฐ๋ ์ ์ ์ฐฝ๊ณ ๋ฅผ ๊ฐ๋ ์ฑ์). ์์ ์์ ๋ฅผ ์ ์ฉํด๋ณด๋ฉด ์ปฌ๋ ์ ์ ๋์ด ์๋ ๋ชจ๋ ์์๋ฅผ ํฌํจํ๋ ค ํ ๊ฒ์ด๋ฏ๋ก ๋ฌดํ ๋ฃจํ๋ฅผ ๋๋ฉด์ ์๋ก์ด ์์๋ฅผ ๊ณ์ฐํ๊ณ ์ถ๊ฐํ๊ธฐ๋ฅผ ๋ฐ๋ณตํ ๊ฒ์ด๋ค. ๊ฒฐ๊ตญ ์๋น์๋ ์์ํ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ ์๊ฒ ๋๋ค.
์คํธ๋ฆผ์ ๋จ ํ๋ฒ๋ง ์๋น ํ ์ ์๋ค.
List<String> title = Arrays.asList(โjava8โ, โinโ, โactionโ);
Stream<String> s = title.stream();
s.forEach(System.out::println); // title์ ๊ฐ ๋จ์ด๋ฅผ ์ถ๋ ฅ
s.forEach(System.out::println); // java.lang.IllegalStateException : ์คํธ๋ฆฝ์ด ์ด๋ฏธ ์๋น๋์๊ฑฐ๋ ๋ซํ
์คํธ๋ฆผ๊ณผ ์ปฌ๋ ์ ์ ์ฒ ํ์ ์ ๊ทผ
์คํธ๋ฆผ์ ์๊ฐ์ ์ผ๋ก ํฉ์ด์ง ๊ฐ์ ์งํฉ์ผ๋ก ๊ฐ์ฃผํ ์ ์๋ค. ๋ฐ๋ฉด ์ปฌ๋ ์ ์ ํน์ ์๊ฐ์ ๋ชจ๋ ๊ฒ์ด ์กด์ฌํ๋ ๊ณต๊ฐ(์ปดํจํฐ ๋ฉ๋ชจ๋ฆฌ)์ ํฉ์ด์ง ๊ฐ์ผ๋ก ๋น์ ํ ์ ์๋ค. for-each ๋ฃจํ ๋ด์์ ๋ฐ๋ณต์๋ฅผ ์ด์ฉํด์ ๊ณต๊ฐ์ ํฉ์ด์ง ์์์ ์ ๊ทผํ ์ ์๋ค.
์ปฌ๋ ์ ๊ณผ ์คํธ๋ฆผ์ ๋ ๋ค๋ฅธ ์ฐจ์ด์ ์ ๋ฐ์ดํฐ ๋ฐ๋ณต ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ด๋ค. ์ปฌ๋ ์ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ฌ์ฉ์๊ฐ ์ง์ ์์๋ฅผ ๋ฐ๋ณตํด์ผ ํ๋ค. ์ด๋ฅผ ์ธ๋ถ ๋ฐ๋ณต์ด๋ผ๊ณ ํ๋ค. ๋ฐ๋ฉด ์คํธ๋ฆผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ฐ๋ณต์ ์์์ ์ฒ๋ฆฌํ๊ณ ๊ฒฐ๊ณผ ์คํธ๋ฆผ๊ฐ์ ์ด๋๊ฐ์ ์ ์ฅํด์ฃผ๋ ๋ด๋ถ ๋ฐ๋ณต์ ์ฌ์ฉํ๋ค. ์คํธ๋ฆผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ด๋ถ ๋ฐ๋ณต์ ๋ฐ์ดํฐ ํํ๊ณผ ํ๋์จ์ด๋ฅผ ํ์ฉํ ๋ณ๋ ฌ์ฑ ๊ตฌํ์ ์๋์ผ๋ก ์ ํํ๋ค. ๋ฐ๋ฉด for-each๋ฅผ ์ด์ฉํ๋ ์ธ๋ถ ๋ฐ๋ณต์์๋ ๋ณ๋ ฌ์ฑ์ ์ค์ค๋ก ๊ด๋ฆฌํด์ผ ํ๋ค.
์คํธ๋ฆผ ์ฐ์ฐ
์คํธ๋ฆผ ์ธํฐํ์ด์ค์ ์ฐ์ฐ์ ํฌ๊ฒ ๋ ๊ฐ์ง๋ก ๊ตฌ๋ถํ ์ ์๋ค.
List<String> threeHighCaloricDishNames = menu.stream() // ๋ฉ๋ด(์๋ฆฌ ๋ฆฌ์คํธ)์์ ์คํธ๋ฆผ์ ์ป๋๋ค.
.filter(d -> d.getCalories() > 300) // ์ค๊ฐ ์ฐ์ฐ
.map(Dish::getName) // ์ค๊ฐ ์ฐ์ฐ
.limit(3) // ์ค๊ฐ ์ฐ์ฐ
.collect(toList()); // ์คํธ๋ฆผ์ ๋ฆฌ์คํธ๋ก ๋ณํ. ์ต์ข
์ฐ์ฐ
filter
, map
, limit
๋ ์๋ก ์ฐ๊ฒฐ๋์ด ํ์ดํ๋ผ์ธ์ ํ์ฑํ๋ค.
collect
๋ก ํ์ดํ๋ผ์ธ์ ์คํํ ๋ค์์ ๋ซ๋๋ค.
์ฐ๊ฒฐํ ์ ์๋ ์คํธ๋ฆผ ์ฐ์ฐ์ ์ค๊ฐ ์ฐ์ฐ์ด๋ผ๊ณ ํ๋ฉฐ, ์คํธ๋ฆผ์ ๋ซ๋ ์ฐ์ฐ์ ์ต์ข ์ฐ์ฐ์ด๋ผ๊ณ ํ๋ค. ์ ์คํธ๋ฆผ์ ์ฐ์ฐ์ ๋ ๊ฐ์ง๋ก ๊ตฌ๋ถํ๋ ๊ฒ์ผ๊น?
์ค๊ฐ ์ฐ์ฐ
filter
๋ sorted
๊ฐ์ ์ค๊ฐ ์ฐ์ฐ์ ๋ค๋ฅธ ์คํธ๋ฆผ์ ๋ฐํํ๋ค. ๋ฐ๋ผ์ ์ฌ๋ฌ ์ค๊ฐ ์ฐ์ฐ์ ์ฐ๊ฒฐํด์ ์ง์๋ฅผ ๋ง๋ค ์ ์๋ค. ์ค๊ฐ ์ฐ์ฐ์ ์ค์ํ ํน์ง์ ๋จ๋ง ์ฐ์ฐ์ ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ์คํํ๊ธฐ ์ ๊น์ง๋ ์๋ฌด ์ฐ์ฐ๋ ์ํํ์ง ์๋๋ค๋ ๊ฒ, ์ฆ ๊ฒ์ด๋ฅด๋ค๋ ๊ฒ์ด๋ค. ์ค๊ฐ ์ฐ์ฐ์ ํฉ์น ๋ค์์ ํฉ์ณ์ง ์ค๊ฐ ์ฐ์ฐ์ ์ต์ข
์ฐ์ฐ์ผ๋ก ํ ๋ฒ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ด๋ค.
// ์ ํ ์ฝ๋์๋ ์ด์ ๊ฐ์ ์ถ๋ ฅ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ง ์๋๊ฒ ์ข๋ค. ๊ทธ๋ฌ๋ ํ์ต์ฉ์ผ๋ก๋ ๋งค์ฐ ์ข์ ๊ธฐ๋ฒ์ด๋ค.
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);
// filteringpork
// mappingpork
// filteringbeef
// mappingbeef
// filteringchicken
// mappingchicken
// [pork, beef, chicken]
์คํธ๋ฆผ์ ๊ฒ์ผ๋ฅธ ํน์ฑ ๋๋ถ์ ๋ช ๊ฐ์ง ์ต์ ํ ํจ๊ณผ๋ฅผ ์ป์ ์ ์์๋ค. ์ฒซ์งธ, 300์นผ๋ก๋ฆฌ๊ฐ ๋๋ ์๋ฆฌ๋ ์ฌ๋ฌ ๊ฐ์ง๋ง ์ค์ง ์ฒ์ 3๊ฐ๋ง ์ ํ๋์๋ค. ์ด๋ limit
์ฐ์ฐ ๊ทธ๋ฆฌ๊ณ ์ผํธ์ํท์ด๋ผ ๋ถ๋ฆฌ๋ ๊ธฐ๋ฒ ๋๋ถ์ด๋ค. ๋์งธ, filter
์ map
์ ์๋ก ๋ค๋ฅธ ์ฐ์ฐ์ด์ง๋ง ํ ๊ณผ์ ์ผ๋ก ๋ณํฉ๋์๋ค(์ด ๊ธฐ๋ฒ์ ๋ฃจํ ํจ์ ์ด๋ผ๊ณ ํ๋ค).
์ต์ข ์ฐ์ฐ
์ต์ข
์ฐ์ฐ์ ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์์ ๊ฒฐ๊ณผ๋ฅผ ๋์ถํ๋ค. ๋ณดํต ์ต์ข
์ฐ์ฐ์ ์ํด List
, Integer
, void
๋ฑ ์คํธ๋ฆผ ์ด์ธ์ ๊ฒฐ๊ณผ๊ฐ ๋ฐํ๋๋ค. ์๋ฅผ ๋ค์ด ํ์ดํ๋ผ์ธ์์ forEach
๋ ์์ค์ ๊ฐ ์๋ฆฌ์ ๋๋ค๋ฅผ ์ ์ฉํ ๋ค์์ void
๋ฅผ ๋ฐํํ๋ ์ต์ข
์ฐ์ฐ์ด๋ค. System.out.println
์ forEach
์ ๋๊ฒจ์ฃผ๋ฉด menu์์ ๋ง๋ ์คํธ๋ฆผ์ ๋ชจ๋ ์๋ฆฌ๋ฅผ ์ถ๋ ฅํ๋ค. menu.stream().forEach(System.out::println);
์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ๊ฐ๋ ์ ๋น๋ ํจํด๊ณผ ๋น์ทํ๋ค.
์ค๊ฐ ์ฐ์ฐ
์ฐ์ฐ | ํ์ | ๋ฐํํ์ | ์ฐ์ฐ์ ์ธ์ |
---|---|---|---|
filter | ์ค๊ฐ์ฐ์ฐ | Stream<T> | Predicate<T> |
map | ์ค๊ฐ์ฐ์ฐ | Stream<T> | Function<T, R> |
limit | ์ค๊ฐ์ฐ์ฐ | Stream<T> | - |
sorted | ์ค๊ฐ์ฐ์ฐ | Stream<T> | Comparator<T> |
distinct | ์ค๊ฐ์ฐ์ฐ | Stream<T> | - |
์ต์ข ์ฐ์ฐ
์ฐ์ฐ | ํ์ | ๋ชฉ์ |
---|---|---|
forEach | ์ต์ข ์ฐ์ฐ | ์คํธ๋ฆผ์ ๊ฐ ์์๋ฅผ ์๋นํ๋ฉด์ ๋๋ค๋ฅผ ์ ์ฉํ๋ค. void ๋ฅผ ๋ฐํํ๋ค. |
count | ์ต์ข ์ฐ์ฐ | ์คํธ๋ฆผ์ ์์ ๊ฐ์๋ฅผ ๋ฐํํ๋ค. long ์ ๋ฐํํ๋ค. |
collect | ์ต์ข ์ฐ์ฐ | ์คํธ๋ฆผ์ reduce ํด์ ๋ฆฌ์คํธ, ๋งต, ์ ์ ํ์์ ์ปฌ๋ ์
์ ๋ง๋ ๋ค. |
5์ฅ - ์คํธ๋ฆผ ํ์ฉ
ํํฐ๋ง ์ฌ๋ผ์ด์ฑ
filter
๋ฉ์๋๋ ํ๋ ๋์ผ์ดํธ(๋ถ๋ฆฐ์ ๋ฐํํ๋ ํจ์)๋ฅผ ์ธ์๋ก ๋ฐ์์ ํ๋ ๋์ผ์ดํธ์ ์ผ์นํ๋ ๋ชจ๋ ์์๋ฅผ ํฌํจํ๋ ์คํธ๋ฆผ์ ๋ฐํํ๋ค.
// ์ฑ์ ์๋ฆฌ์ธ์ง ํ์ธํ๋ ๋ฉ์๋ ๋ ํผ๋ฐ์ค
List<Dish> vegetarianMenu = menu.stream()
.filter(Dish::isVegetarian)
.collect(toList());
๊ณ ์ ์์ ํํฐ๋ง
List<Integer> numbers = Arrays.asList(1,2,1,1,3,4,5);
numbers.stream().filter(i -> i%2 == 0).distinct().forEach(System.out::println);
์คํธ๋ฆผ ์ถ์
List<Dish> vegetarianMenu = menu.stream()
.filter(d -> d.getCalories() > 300)
.limit(3)
.collect(toList());
์์ ๊ฑด๋๋ฐ๊ธฐ
// 300์นผ๋ก๋ฆฌ ์ด์์ ์ฒ์ ๋ ์๋ฆฌ๋ฅผ ๊ฑด๋ ๋ด ๋ค์์ 300์นผ๋ก๋ฆฌ๊ฐ ๋๋ ๋๋จธ์ง ์๋ฆฌ๋ฅผ ๋ฐํํ๋ค.
List<Dish> vegetarianMenu = menu.stream()
.filter(d -> d.getCalories() > 300)
.skip(2)
.collect(toList());
๋งคํ
ํน์ ๊ฐ์ฒด์์ ํน์ ๋ฐ์ดํฐ๋ฅผ ์ ํํ๋ ์์
์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ณผ์ ์์ ์์ฃผ ์ํ๋๋ ์ฐ์ฐ์ด๋ค. ์๋ฅผ ๋ค์ด SQL์ ํ
์ด๋ธ์์ ํน์ ์ด๋ง ์ ํํ ์ ์๋ค. ์คํธ๋ฆผ API์ map
๊ณผ flatMap
๋ฉ์๋๋ ํน์ ๋ฐ์ดํฐ๋ฅผ ์ ํํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
์คํธ๋ฆผ์ ๊ฐ ์์์ ํจ์ ์ ์ฉํ๊ธฐ
List<String> words = Arrays.asList("Hello", "World");
List<String> str = words.stream()
.map(w -> w.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(toList());
System.out.println(str);
์คํธ๋ฆผ ํ๋ฉดํ
๋ฉ์๋ map์ ์ด์ฉํด์ ๋ฆฌ์คํธ์ ๊ฐ ๋จ์ด์ ๊ธธ์ด๋ฅผ ๋ฐํํ๋ ๋ฐฉ๋ฒ์ ํ์ธํ๋ค. ์ด๋ฅผ ์์ฉํด์ ๋ฆฌ์คํธ์์ ๊ณ ์ ๋ฌธ์๋ก ์ด๋ฃจ์ด์ง ๋ฆฌ์คํธ๋ฅผ ๋ฐํํด๋ณด์. ์๋ฅผ ๋ค์ด [โHelloโ, โWorldโ]
๋ฆฌ์คํธ๊ฐ ์๋ค๋ฉด ๊ฒฐ๊ณผ๋ก [โHโ,โeโ,โlโ,โoโ,โWโ,โrโ,โdโ]
๋ฅผ ํฌํจํ๋ ๋ฆฌ์คํธ๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค. ๋ค์์ฒ๋ผ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
words.stream()
.map(word -> word.split(""))
.distinct()
.collect(toList());
ํ์ง๋ง ์ ์ฝ๋์์ map
์ผ๋ก ์ ๋ฌํ ๋๋ค๋ ๊ฐ ๋จ์ด์ String์ ๋ฐํํ๋ค๋ ๋ฌธ์ ๊ฐ ์๋ค. ๋ฐ๋ผ์ map
๋ฉ์๋๊ฐ ๋ฐํํ ์คํธ๋ฆผ์ ํ์์ Stream<String[]>
์ด๋ค. ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ฒ์ ๋ฌธ์์ด์ ์คํธ๋ฆผ์ ํํํ Stream<String>
์ด๋ค. ๋คํํ flatMap
์ด๋ผ๋ ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
๋จผ์ ๊ฐ ๋จ์ด๋ฅผ ๊ฐ๋ณ ๋ฌธ์์ด๋ก ์ด๋ฃจ์ด์ง ๋ฐฐ์ด๋ก ๋ง๋ ๋ค์์ ๊ฐ ๋ฐฐ์ด์ ๋ณ๋ก์ ์คํธ๋ฆผ์ผ๋ก ๋ง๋ค์ด์ผ ํ๋ค.
List<String> words = Arrays.asList("Hello", "World");
List<String> str = words.stream()
.map(w -> w.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(toList());
System.out.println(str);
flatMap
์ ๊ฐ ๋ฐฐ์ด์ ์คํธ๋ฆผ์ด ์๋๋ผ ์คํธ๋ฆผ์ ์ฝํ
์ธ ๋ก ๋งคํํ๋ค. ์ฆ, ์์ฑ๋ ์คํธ๋ฆผ์ ํ๋์ ์คํธ๋ฆผ์ผ๋ก ํ๋ฉดํํ๋ค.
๊ฒ์๊ณผ ๋งค์นญ
ํน์ ์์ฑ์ด ๋ฐ์ดํฐ ์งํฉ์ ์๋์ง ์ฌ๋ถ๋ฅผ ๊ฒ์ํ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ ์์ฃผ ์ฌ์ฉ๋๋ค. ์คํธ๋ฆผ API๋ AllMatch
, anyMatch
, noneMatch
, findFirst
, findAny
๋ฑ ๋ค์ํ ์ ํธ๋ฆฌํฐ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.
// ํ๋ ๋์ผ์ดํธ๊ฐ ์ฃผ์ด์ง ์คํธ๋ฆผ์์ ์ ์ด๋ ํ ์์์ ์ผ์นํ๋์ง ํ์ธํ ๋ anyMatch ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ค.
if(menu.stream().anyMatch(Dish::isVegetarian) { // anyMatch๋ ๋ถ๋ฆฐ์ ๋ฐํํ๋ฏ๋ก ์ต์ข
์ฐ์ฐ์ด๋ค.
...
}
// ํ๋ ๋์ผ์ดํธ๊ฐ ๋ชจ๋ ์์์ ์ผ์นํ๋์ง ๊ฒ์ฌ
boolean isHealthy = menu.stream().allMatch(d -> d.getCalories() < 1000);
//noneMatch
boolean isHealthy = menu.stream().noneMatch(d -> d.getCalories() < 1000);
anyMatch
, allMatch
, noneMatch
์ธ ๊ฐ์ง ๋ฉ์๋๋ ์คํธ๋ฆผ ์ผํธ์ํท ๊ธฐ๋ฒ, ์ฆ ์๋ฐ์ &&
, ||
์ ๊ฐ์ ์ฐ์ฐ์ ํ์ฉํ๋ค.
์ผํธ์ํท ํ๊ฐ
๋๋ก๋ ์ ์ฒด ์คํธ๋ฆฌ๋ฏ ์ฒ๋ฆฌํ์ง ์์๋๋ผ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์๋ค. ์๋ฅผ ๋ค์ด ์ฌ๋ฌ and ์ฐ์ฐ์ผ๋ก ์ฐ๊ฒฐ๋ ์ปค๋ค๋ ๋ถ๋ฆฐ ํํ์์ ํ๊ฐํ๋ค๊ณ ๊ฐ์ ํ์. ํํ์์์ ํ๋๋ผ๋ ๊ฑฐ์ง์ด๋ผ๋ ๊ฒฐ๊ณผ๊ฐ ๋์ค๋ฉด ๋๋จธ์ง ํํ์์ ๊ฒฐ๊ณผ์ ์๊ด์์ด ์ ์ฒด ๊ฒฐ๊ณผ๋ ๊ฑฐ์ง์ด ๋๋ค. ์ด๋ฌํ ์ํฉ์ ์ผํธ์ํท์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
allMatch
, noneMatch
, findFirst
, findAny
๋ฑ์ ์ฐ์ฐ์ ๋ชจ๋ ์คํธ๋ฆฝ์ ์์๋ฅผ ์ฒ๋ฆฌํ์ง ์๊ณ ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์๋ค. ์ํ๋ ์์๋ฅผ ์ฐพ์์ผ๋ฉด ์ฆ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก ์คํธ๋ฆผ์ ๋ชจ๋ ์์๋ฅผ ์ฒ๋ฆฌํ ํ์ ์์ด ์ฃผ์ด์ง ํฌ๊ธฐ์ ์คํธ๋ฆผ์ ์์ฑํ๋ limit๋ ์ผํธ์ํท ์ฐ์ฐ์ด๋ค. ํนํ ๋ฌดํํ ์์๋ฅผ ๊ฐ์ง ์คํธ๋ฆผ์ ์ ํํ ํฌ๊ธฐ๋ก ์ค์ผ ์ ์๋ ์ ์ฉํ ์ฐ์ฐ์ด๋ค.
์์ ๊ฒ์
findAny
๋ฉ์๋๋ ํ์ฌ ์คํธ๋ฆผ์์ ์์์ ์์๋ฅผ ๋ฐํํ๋ค.
Optional<Dish> dish = menu.stream().filter(Dish::isVegetarian).findAny();
๊ทธ๋ฐ๋ฐ ์ ์ฝ๋์ ์ฌ์ฉ๋ Optional
์ ๋ฌด์์ผ๊น? Optional<T>
ํด๋์ค๋ ๊ฐ์ ์กด์ฌ๋ ๋ถ์ฌ ์ฌ๋ถ๋ฅผ ํํํ๋ ์ปจํ
์ด๋ ํด๋์ค๋ค. ์ด์ ์์ ์์ findAny
๋ ์๋ฌด ์์๋ ๋ฐํํ์ง ์์ ์ ์๋ค. null์ ์ฝ๊ฒ ์๋ฌ๋ฅผ ์ผ์ผํฌ ์ ์์ผ๋ฏ๋ก ์๋ฐ8 ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค๊ณ์๋ Optional<T>
๋ผ๋ ๊ธฐ๋ฅ์ ๋ง๋ค์๋ค.
isPresent()
๋ Optional
์ด ๊ฐ์ ํฌํจํ๋ฉด ์ฐธ(true
)์ ๋ฐํํ๊ณ , ๊ฐ์ ํฌํจํ์ง ์์ผ๋ฉด ๊ฑฐ์ง(false
)๋ฅผ ๋ฐํํ๋ค. ifPresent(Consumer<T> block)
์ ๊ฐ์ด ์์ผ๋ฉด ์ฃผ์ด์ง ๋ธ๋ก์ ์คํํ๋ค.
menu.stream()
.filter(Dish::isVegetarian)
.findAny() // Optional<Dish> ๋ฐํ
.ifPresent(d -> System.out.println(d.getName()); // ๊ฐ์ด ์์ผ๋ฉด ์ถ๋ ฅํ๊ณ , ์์ผ๋ฉด ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋๋ค.
T get()
์ ๊ฐ์ด ์กด์ฌํ๋ฉด ๊ฐ์ ๋ฐํํ๊ณ ๊ฐ์ด ์์ผ๋ฉด NoSuchElementException
์ ์ผ์ผํจ๋ค. T orElse(T other)
๋ ๊ฐ์ด ์์ผ๋ฉด ๊ฐ์ ๋ฐํํ๊ณ , ๊ฐ์ด ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ์ ๋ฐํํ๋ค.
๊ทธ๋ฐ๋ฐ ์ findFirst
์ findAny
๋ ๊ฐ์ง ๋ฉ์๋ ๋ชจ๋ ํ์ํ ๊น? ๋ฐ๋ก ๋ณ๋ ฌ์ฑ ๋๋ฌธ์ด๋ค. ๋ณ๋ ฌ ์คํ์์๋ ์ฒซ ๋ฒ์งธ ์์๋ฅผ ์ฐพ๊ธฐ ์ด๋ ต๋ค. ๋ฐ๋ผ์ ์์์ ๋ฐํ ์์๊ฐ ์๊ด์๋ค๋ฉด ๋ณ๋ ฌ ์คํธ๋ฆผ์์๋ ์ ์ฝ์ด ์ ์ findAny
๋ฅผ ์ฌ์ฉํ๋ค.
๋ฆฌ๋์ฑ
๋ชจ๋ ์คํธ๋ฆผ ์์๋ฅผ ์ฒ๋ฆฌํด์ ๊ฐ์ผ๋ก ๋์ถํ๋ ๊ฒ์ ๋ฆฌ๋์ฑ ์ฐ์ฐ์ด๋ผ๊ณ ํ๋ค.
์์์ ํฉ
int sum = numbers.stream().reduce(0, (a,b) -> a+b);
reduce
๋ฅผ ์ด์ฉํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฐ๋ณต๋ ํจํด์ ์ถ์ํํ ์ ์๋ค. reduce
๋ ๋ ๊ฐ์ ์ธ์๋ฅผ ๊ฐ๋๋ค. ์ด๊ธฐ๊ฐ 0๊ณผ ๋ ์์๋ฅผ ์กฐํฉํด์ ์๋ก์ด ๊ฐ์ ๋ง๋๋ BinaryOperator<T>
. ๋ฉ์๋ ๋ ํผ๋ฐ์ค๋ฅผ ์ด์ฉํด์ ์ด ์ฝ๋๋ฅผ ์ข ๋ ๊ฐ๊ฒฐํ๊ฒ ๋ง๋ค ์ ์๋ค. ์๋ฐ 8์์๋ Integer
ํด๋์ค์ ๋ ์ซ์๋ฅผ ๋ํ๋ ์ ์ sum ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค. int sum = numbers.stream().reduce(0,Integer::sum);
์ด๊ธฐ๊ฐ์ ๋ฐ์ง ์๋๋ก ์ค๋ฒ๋ก๋๋ reduce
๋ ์๋ค. ๊ทธ๋ฌ๋ ์ด reduce
๋ Optional
๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. Optional<Integer> sum = numbers.stream().reduce((a,b)->(a+b));
์คํธ๋ฆผ์ ์๋ฌด ์์๋ ์๋ ์ํฉ์ด๋ผ๋ฉด ์ด๊ธฐ๊ฐ์ด ์์ผ๋ฏ๋ก reduce
๋ ํฉ๊ณ๋ฅผ ๋ฐํํ ์ ์๋ค. ๋ฐ๋ผ์ ํฉ๊ณ๊ฐ ์์์ ๊ฐ๋ฆฌํฌ ์ ์๋๋ก Opti`onal ๊ฐ์ฒด๋ก ๊ฐ์ผ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ค.
์ต๋/์ต์๊ฐ
Optional<Integer> max = numbers.stream().reduce(Integer::max);
reduce ๋ฉ์๋์ ์ฅ์ ๊ณผ ๋ณ๋ ฌํ
reduce๋ฅผ ์ด์ฉํ๋ฉด ๋ด๋ถ ๋ฐ๋ณต์ด ์ถ์ํ๋๋ฉด์ ๋ด๋ถ ๊ตฌํ์์ ๋ณ๋ ฌ๋ก reduce๋ฅผ ์คํํ ์ ์๊ฒ ๋๋ค. ๋ฐ๋ณต์ ์ธ ํฉ๊ณ์์๋ sum ๋ณ์๋ฅผ ๊ณต์ ํด์ผ ํ๋ฏ๋ก ์ฝ๊ฒ ๋ณ๋ ฌํ ํ๊ธฐ ์ด๋ ต๋ค.
์คํธ๋ฆผ ์ฐ์ฐ: ์ํ ์์๊ณผ ์ํ ์์
map
, filter
๋ฑ์ ์
๋ ฅ ์คํธ๋ฆผ์์ ๊ฐ ์์๋ฅผ ๋ฐ์ 0 ๋๋ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅ ์คํธ๋ฆผ์ผ๋ก ๋ณด๋ธ๋ค. ๋ฐ๋ผ์ (์ฌ์ฉ์๊ฐ ์ ๊ณตํ ๋๋ค๋ ๋ฉ์๋ ๋ ํผ๋ฐ์ค๊ฐ ๋ด๋ถ์ ์ธ ๊ฐ๋ณ ์ํ๋ฅผ ๊ฐ์ง ์๋๋ค๋ ๊ฐ์ ํ์) ์ด๋ค์ ๋ณดํต ์ํ๊ฐ ์๋, ์ฆ ๋ด๋ถ ์ํ๋ฅผ ๊ฐ์ง ์๋ ์ฐ์ฐ์ด๋ค(stateless operation). ํ์ง๋ง reduce
, sum
, max
๊ฐ์ ์ฐ์ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋์ ํ ๋ด๋ถ ์ํ๊ฐ ํ์ํ๋ค. ์คํธ๋ฆผ์์ ์ฒ๋ฆฌํ๋ ์์ ์์ ๊ด๊ณ์์ด ๋ด๋ถ ์ํ์ ํฌ๊ธฐ๋ ํ์ ๋์ด ์๋ค.
sorted
๋ distinct
๊ฐ์ ์ฐ์ฐ์ filter
๋ map
์ฒ๋ผ ์คํธ๋ฆผ์ ์
๋ ฅ์ผ๋ก ๋ฐ์ ๋ค๋ฅธ ์คํธ๋ฆผ์ ์ถ๋ ฅํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์๋ค. ํ์ง๋ง ์คํธ๋ฆผ์ ์์๋ฅผ ์ ๋ ฌํ๊ฑฐ๋ ์ค๋ณต์ ์ ๊ฑฐํ๋ ค๋ฉด ๊ณผ๊ฑฐ์ ์ด๋ ฅ์ ์๊ณ ์์ด์ผ ํ๋ค. ๋ฐ๋ผ์ ์ด๋ฌํ ์ฐ์ฐ์ ๋ด๋ถ ์ํ๋ฅผ ๊ฐ๋ ์ฐ์ฐ์ผ๋ก ๊ฐ์ฃผํ ์ ์๋ค.
์ค์ ์ฐ์ต
Trader raoul = new Trader("Raoul","Cambridge");
Trader mario = new Trader("Mario","Milan");
Trader alan = new Trader("Alan","Cambridge");
Trader brian = new Trader("Brian","Cambridge");
List<Transaction> transactions = Arrays.asList(
new Transaction(brian,2011,300),
new Transaction(raoul,2012,1000),
new Transaction(raoul,2011,400),
new Transaction(mario,2012,710),
new Transaction(mario,2012,700),
new Transaction(alan,2012,950)
);
//1๋ฒ 2011๋
์ ์ผ์ด๋ ๋ชจ๋ ํธ๋์ญ์
์ ์ฐพ์ ๊ฐ์ ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ฆฌํ๋ผ
List<String> list = transactions.stream()
.filter(t -> t.getYear() ==2011)
.map(Transaction::toString)
.sorted()
.collect(toList());
System.out.println("1๋ฒ"+list);
//2๋ฒ ๊ฑฐ๋์๊ฐ ๊ทผ๋ฌดํ๋ ๋ชจ๋ ๋์๋ฅผ ์ค๋ณต ์์ด ๋์ดํ์์ค
List<String> cities = transactions.stream()
.map(t -> t.getTrader().getCity())
.distinct()
.collect(toList());
System.out.println("2๋ฒ"+cities);
//3๋ฒ Cambridge์์ ๊ทผ๋ฌดํ๋ ๋ชจ๋ ๊ฑฐ๋์๋ฅผ ์ฐพ์์ ์ด๋ฆ์์ผ๋ก ์ ๋ ฌํ์์ค
List<String> tradersInCombridege = transactions.stream()
.filter(t -> t.getTrader().getCity().equals("Cambridge"))
.map(t -> t.getTrader().getName())
.sorted()
.distinct()
.collect(toList());
System.out.println("3๋ฒ"+tradersInCombridege);
List<Trader> tradersInCambridege2 = transactions.stream()
.map(Transaction::getTrader)
.filter(t -> t.getCity().equals("Cambridge"))
.sorted(comparing(Trader::getName))
.distinct()
.collect(toList());
System.out.println("3๋ฒ-2 "+tradersInCambridege2);
//4๋ฒ ๋ชจ๋ ๊ฑฐ๋์์ ์ด๋ฆ์ ์ํ๋ฒณ์์ผ๋ก ์ ๋ ฌํด์ ๋ฐํํ์์ค.
String traders = transactions.stream()
.map(t ->t.getTrader().getName())
.sorted()
.distinct()
.reduce("",(a,b)->a+b);
System.out.println("4๋ฒ "+traders);
String traders2 = transactions.stream()
.map(t ->t.getTrader().getName())
.sorted()
.distinct()
.collect(joining());
System.out.println("4๋ฒ-2 "+traders2);
//5๋ฒ ๋ฐ๋ผ๋
ธ์ ๊ฑฐ๋์๊ฐ ์๋๊ฐ?
boolean milanoTrader = transactions.stream()
.anyMatch(t -> t.getTrader().getCity().equals("Milan"));
System.out.println("5๋ฒ"+milanoTrader);
//6๋ฒ Cambridge์ ๊ฑฐ์ฃผํ๋ ๊ฑฐ๋์์ ๋ชจ๋ ํธ๋์ญ์
๊ฐ์ ์ถ๋ ฅํ์์ค
List<String> transactionValue = transactions.stream()
.map(t -> t.getTrader().getCity())
.distinct()
.collect(toList());
System.out.println("6๋ฒ" +transactionValue);
//7๋ฒ ์ ์ฒด ํธ๋์ญ์
์ค ์ต๋๊ฐ์ ์ผ๋ง์ธ๊ฐ
int max = transactions.stream().map(i -> i.getValue()).reduce(0,Integer::max);
System.out.println("7๋ฒ ์ต๋๊ฐ :"+max);
//8๋ฒ ์ ์ฒด ํธ๋์ญ์
์ค ์ต์๊ฐ
Optional<Integer> min = transactions.stream().map(i->i.getValue()).reduce(Integer::min);
System.out.println("8๋ฒ ์ต์๊ฐ :"+min.get());
์ซ์ํ ์คํธ๋ฆผ
์คํธ๋ฆผ API ์ซ์ ์คํธ๋ฆผ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋๋ก ์ธ ๊ฐ์ง ๊ธฐ๋ณธํ ํนํ ์คํธ๋ฆผ์ ์ ๊ณตํ๋ค. ๋ฐ์ฑ ๋น์ฉ์ ํผํ ์ ์๋๋ก โint
์์์ ํนํ๋ IntStream
โ, โdouble
์์์ ํนํ๋ DoubleStream
โ, โlong
์์์ ํนํ๋ LongStream
โ์ ์ ๊ณตํ๋ค. ํนํ ์คํธ๋ฆผ์ ์ค์ง ๋ฐ์ฑ ๊ณผ์ ์์ ์ผ์ด๋๋ ํจ์จ์ฑ๊ณผ ๊ด๋ จ ์์ผ๋ฉฐ ์คํธ๋ฆผ์ ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง ์๋๋ค๋ ์ฌ์ค์ ๊ธฐ์ตํ์.
์ซ์ ์คํธ๋ฆผ์ผ๋ก ๋งคํ
์คํธ๋ฆผ์ ํนํ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ ๋๋ mapToInt
, mapToDouble
, mapToLong
์ธ ๊ฐ์ง ๋ฉ์๋๋ฅผ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ค. ์ด๋ค ๋ฉ์๋๋ map
๊ณผ ์ ํํ ๊ฐ์ ๊ธฐ๋ฅ์ ์ํํ์ง๋ง, Stream<T>
๋์ ํนํ๋ ์คํธ๋ฆผ์ ๋ฐํํ๋ค.
int calories = menu.stream().mapToInt(Dish::getCalories).sum();
mapToInt
๋ฉ์๋๋ ๊ฐ ์๋ฆฌ์์ ๋ชจ๋ ์นผ๋ก๋ฆฌ๋ฅผ ์ถ์ถํ ๋ค์์ IntStream
(Stream<Integer>
๊ฐ ์๋)์ ๋ฐํํ๋ค. ๋ฐ๋ผ์ IntStream
์ธํฐํ์ด์ค์์ ์ ๊ณตํ๋ sum
๋ฉ์๋๋ฅผ ์ด์ฉํด์ ์นผ๋ก๋ฆฌ ํฉ๊ณ๋ฅผ ๊ณ์ฐํ ์ ์๋ค. ์คํธ๋ฆผ์ด ๋น์ด ์์ผ๋ฉด sum
์ ๊ธฐ๋ณธ๊ฐ 0์ ๋ฐํํ๋ค. IntStream
์ max
, min
, average
๋ฑ ๋ค์ํ ์ ํธ๋ฆฌํฐ ๋ฉ์๋๋ ์ง์ํ๋ค.
๊ฐ์ฒด ์คํธ๋ฆผ์ผ๋ก ๋ณต์ํ๊ธฐ
boxed ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ํนํ ์คํธ๋ฆผ์ ์ผ๋ฐ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ ์ ์๋ค.
IntStream intStream = menu.stream().mapToInt(Dish::getCalories); // ์คํธ๋ฆผ์ ์ซ์ ์คํธ๋ฆผ์ผ๋ก ๋ณํ
Stream<Integer> stream = intStream.boxed(); // ์ซ์ ์คํธ๋ฆผ์ ์คํธ๋ฆผ์ผ๋ก ๋ณํ
๊ธฐ๋ณธ๊ฐ : OptionalInt
ํฉ๊ณ ์์ ์์๋ 0์ด๋ผ๋ ๊ธฐ๋ณธ๊ฐ์ด ์์์ผ๋ฏ๋ก ๋ณ ๋ฌธ์ ๊ฐ ์์๋ค. ํ์ง๋ง IntStream
์์ ์ต๋๊ฐ์ ์ฐพ์ ๋๋ 0์ด๋ผ๋ ๊ธฐ๋ณธ๊ฐ ๋๋ฌธ์ ์๋ชป๋ ๊ฒฐ๊ณผ๊ฐ ๋์ถ๋ ์ ์๋ค. ์คํธ๋ฆผ์ ์์๊ฐ ์๋ ์ํฉ๊ณผ ์ค์ ์ต๋๊ฐ์ด 0์ธ ์ํฉ์ ์ด๋ป๊ฒ ๊ตฌ๋ณํ ์ ์์๊น. OptionalInt
, OptionalDouble,
OptionalLong` ์ธ ๊ฐ์ง ๊ธฐ๋ณธํ ํนํ ์คํธ๋ฆผ ๋ฒ์ ์ด ์๋ค.
OptionalInt maxCalories = menu.stream().maxToInt(Dish::getCalories).max();
int max = maxCalories.orElse(1); // ๊ฐ์ด ์์ ๋ ๊ธฐ๋ณธ ์ต๋๊ฐ์ ๋ช
์์ ์ผ๋ก ์ค์
์ซ์ ๋ฒ์
ํ๋ก๊ทธ๋จ์์๋ ํน์ ๋ฒ์์ ์ซ์๋ฅผ ์ด์ฉํด์ผ ํ๋ ์ํฉ์ด ์์ฃผ ๋ฐ์ํ๋ค. ์๋ฐ8์ IntStream
๊ณผ LongStream
์์๋ range
์ rangeClosed
๋ผ๋ ๋ ๊ฐ์ง ์ ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค. ๋ ๋ฉ์๋ ๋ชจ๋ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์์๊ฐ์, ๋ ๋ฒ์งธ ์ธ์๋ก ์ข
๋ฃ๊ฐ์ ๊ฐ๋๋ค. range
๋ฉ์๋๋ ์์๊ฐ๊ณผ ์ข
๋ฃ๊ฐ์ด ๊ฒฐ๊ณผ์ ํฌํจ๋์ง ์๋ ๋ฐ๋ฉด rangeClosed
๋ ์์๊ฐ๊ณผ ์ข
๋ฃ๊ฐ์ด ๊ฒฐ๊ณผ์ ํฌํจ๋๋ค๋ ์ ์ด ๋ค๋ฅด๋ค.
IntStream evenNumbers = IntStream.rangeClosed(1,100).filter(n->n%2==0);
System.out.println(evenNumbers.count());
์คํธ๋ฆผ ๋ง๋ค๊ธฐ
๊ฐ์ผ๋ก ์คํธ๋ฆผ ๋ง๋ค๊ธฐ
์์์ ์๋ฅผ ์ธ์๋ฅผ ๋ฐ๋ ์ ์ ๋ฉ์๋ Stream.of
๋ฅผ ์ด์ฉํด์ ์คํธ๋ฆผ์ ๋ง๋ค ์ ์๋ค. ์๋ฅผ ๋ค์ด ๋ค์ ์ฝ๋๋ Stream.of
๋ก ๋ฌธ์์ด ์คํธ๋ฆผ์ ๋ง๋๋ ์์ ๋ค. ์คํธ๋ฆผ์ ๋ชจ๋ ๋ฌธ์์ด์ ๋๋ฌธ์๋ก ๋ณํํ ํ ๋ฌธ์์ด์ ํ๋์ฉ ์ถ๋ ฅํ๋ค.
Stream<String> stream = Stream.of(โjava8โ,โlambdaโ,โinโ,โactionโ);
stream.map(String::toUpperCase).forEach(System.out::println);
๋ค์ ์ฒ๋ผ empty
๋ฉ์๋๋ฅผ ์ด์ฉํด์ ์คํธ๋ฆผ์ ๋น์ธ ์ ์๋ค. Stream<String> emptyStream = Stream.empty();
๋ฐฐ์ด๋ก ์คํธ๋ฆผ ๋ง๋ค๊ธฐ
๋ฐฐ์ด์ ์ธ์๋ก ๋ฐ๋ ์ ์ ๋ฉ์๋ Arrays.stream
์ ์ด์ฉํด์ ์คํธ๋ฆผ์ ๋ง๋ค ์ ์๋ค.
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();
ํ์ผ๋ก ์คํธ๋ฆผ ๋ง๋ค๊ธฐ
ํ์ผ์ ์ฒ๋ฆฌํ๋ I/O ์ฐ์ฐ์ ์ฌ์ฉํ๋ ์๋ฐ์ NIO API๋ ์คํธ๋ฆผ API๋ฅผ ํ์ฉํ ์ ์๋๋ก ์กํ
์ดํธ๋์๋ค. java.nio.file.Files
์ ๋ง์ ์ ์ ๋ฉ์๋๊ฐ ์คํธ๋ฆผ์ ๋ฐํํ๋ค. ์๋ฅผ ๋ค์ด Files.lines
๋ ์ฃผ์ด์ง ํ์ผ์ ํ ์คํธ๋ฆผ์ ๋ฌธ์์ด๋ก ๋ฐํํ๋ค.
long uniqueWords =0;
try(Stream<String> lines = Files.lines(Paths.get(โdata.txtโ), Charset.defaultCharset())) { // ์คํธ๋ฆผ์ ์์์ ์๋์ผ๋ก ํด์ ํ ์ ์๋ AutoClosable์ด๋ค.
uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(โ โ))) // ๋จ์ด ์คํธ๋ฆผ ์์ฑ
.distinct() // ์ค๋ณต ์ ๊ฑฐ
.count(); // ๊ณ ์ ๋จ์ด ์ ๊ณ์ฐ
} catch(IOException e) { } // ํ์ผ์ ์ด๋ค๊ฐ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ์ฒ๋ฆฌ
ํจ์๋ก ๋ฌดํ ์คํธ๋ฆผ ๋ง๋ค๊ธฐ
์คํธ๋ฆผ API๋ ํจ์์์ ์คํธ๋ฆผ์ ๋ง๋ค ์ ์๋ ๋ ๊ฐ์ ์ ์ ๋ฉ์๋ Stream.iterate
์ Stream.generate
๋ฅผ ์ ๊ณตํ๋ค. ๋ ์ฐ์ฐ์ ์ด์ฉํด์ ๋ฌดํ ์คํธ๋ฆผ, ์ฆ ๊ณ ์ ๋ ์ปฌ๋ ์
์์ ๊ณ ์ ๋ ํฌ๊ธฐ์ ์คํธ๋ฆผ์ ๋ง๋ค์๋ ๊ฒ๊ณผ๋ ๋ฌ๋ฆฌ ํฌ๊ธฐ๊ฐ ๊ณ ์ ๋์ง ์์ ์คํธ๋ฆผ์ ๋ง๋ค ์ ์๋ค. iterate
์ generate
์์ ๋ง๋ ์คํธ๋ฆผ์ ์์ฒญํ ๋๋ง๋ค ์ฃผ์ด์ง ํจ์๋ฅผ ์ด์ฉํด์ ๊ฐ์ ๋ง๋ ๋ค. ๋ฐ๋ผ์ ๋ฌด์ ํ์ผ๋ก ๊ฐ์ ๊ณ์ฐํ ์ ์๋ค. ํ์ง๋ง ๋ณดํต ๋ฌดํํ ๊ฐ์ ์ถ๋ ฅํ์ง ์๋๋ก limit(n)
ํจ์๋ฅผ ํจ๊ป ์ฐ๊ฒฐํด์ ์ฌ์ฉํ๋ค.
// iterate๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
Stream.iterate(0, n -> n+2)
.limit(10)
.forEach(System.out::println);
iterate
๋ฉ์๋๋ ์ด๊ธฐ๊ฐ(์์ ์์๋ 0)๊ณผ ๋๋ค(์์ ์์๋ UnaryOperator<T>
์ฌ์ฉ)๋ฅผ ์ธ์๋ก ๋ฐ์์ ์๋ก์ด ๊ฐ์ ๋์์์ด ์์ฐํ ์ ์๋ค. ์์ ์์๋ ๋๋ค n -> n+2
์ฆ ์ด์ ๊ฒฐ๊ณผ์ 2๋ฅผ ๋ํ ๊ฐ์ ๋ฐํํ๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์ง์ ์คํธ๋ฆผ์ ์์ฑํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๊ธฐ์กด ๊ฒฐ๊ณผ์ ์์กดํด์ ์์ฐจ์ ์ผ๋ก ์ฐ์ฐ์ ์ํํ๋ค. iterate
๋ ์์ฒญํ ๋๋ง๋ค ๊ฐ์ ์์ฐํ ์ ์์ผ๋ฉฐ ๋์ด ์์ผ๋ฏ๋ก ๋ฌดํ ์คํธ๋ฆผ์ ๋ง๋ ๋ค. ์ด๋ฌํ ์คํธ๋ฆผ์ ์ธ๋ฐ์ด๋ ์คํธ๋ฆผ์ด๋ผ๊ณ ํํํ๋ค.
// ํผ๋ณด๋์น ์์ด
Stream.iterate(new int[]{0,1},
t -> new int[]{t[1], t[0] + t[1]})
.limit(10)
.map(t -> t[0])
.forEach(System.out::println);
// generate ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
iterate
์ ๋น์ทํ๊ฒ generate
๋ ์๊ตฌํ ๋ ๊ฐ์ ๊ณ์ฐํ๋ ๋ฌดํ ์คํธ๋ฆผ์ ๋ง๋ค ์ ์๋ค. ํ์ง๋ง iterate
์ ๋ฌ๋ฆฌ generate
๋ ์์ฐ๋ ๊ฐ ๊ฐ์ ์ฐ์์ ์ผ๋ก ๊ณ์ฐํ์ง ์๋๋ค. generate
๋ Supplier<T>
๋ฅผ ์ธ์๋ก ๋ฐ์์ ์๋ก์ด ๊ฐ์ ์์ฐํ๋ค.