์คํธ๋ฆผ (Stream)
์ปฌ๋ ์ (collections)๋ก ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋ฃนํํ๊ณ ์ฒ๋ฆฌํ ์ ์๋ค. ์ปฌ๋ ์ ์ ๋ชจ๋ ์๋ฐ ์ดํ๋ฆฌ์ผ์ด์ ์์ ์ฒ๋ฆฌํ๊ณ , ๋๋ถ๋ถ์ ํ๋ก๊ทธ๋๋ฐ ์์ ์ ์ฌ์ฉ๋๊ธฐ ๋๋ฌธ์ ์ค์ํ๋ค.ํ์ง๋ง ์์ง ์๋ฒฝํ ์ปฌ๋ ์ ์ฐ์ฐ์ ์ง์ํ๋ ค๋ฉด ๋ถ์กฑํ๋ค.
์คํธ๋ฆผ์ด๋ ๋ฌด์์ธ๊ฐ
์คํธ๋ฆผ๋ ์๋ฐ 8 API์ ์๋ก ์ถ๊ฐ๋ ๊ธฐ๋ฅ์ด๋ค.
๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์ฝ๋๋ฅผ ์ง์๋ก ํํํ์ฌ ์ ์ธํ์ผ๋ก ์ปฌ๋ ์
๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
์คํธ๋ฆผ์ ์ฌ์ฉํ๋ฉด ๋ฉํฐ์ค๋ ๋ ์ฝ๋๋ฅผ ๊ตฌํํ์ง ์์๋ ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ ์ ์๋ค.
@Test
@DisplayName("์๋ฆฌ ํด๋์ค ์ ๋ ฌํ๊ธฐ")
void sortExample() {
List<Dish> menuList = new ArrayList<>();
menuList.add(new Dish(100,"๋ญ๊ฐ์ด์ด"));
menuList.add(new Dish(1500, "์นํจ"));
menuList.add(new Dish(500, "์คํ"));
List<Dish> lowCaloricDishes = new ArrayList<>();
for (Dish lowCaloricDish : menuList) {
if(lowCaloricDish.getCalories() < 1000) {
lowCaloricDishes.add(lowCaloricDish);
}
}
Collections.sort(lowCaloricDishes, Comparator.comparingInt(Dish::getCalories));
List<String> lowCalDishesName = new ArrayList<>();
for (Dish lowCaloricDish : lowCaloricDishes) {
lowCalDishesName.add(lowCaloricDish.getName());
}
}
์ ์์ ์์๋ lowCaloricDishes
๋ผ๋ ๊ฐ๋น์ง ๋ณ์๋ฅผ ์ฌ์ฉํด์ ์ปจํ
์ด๋ ์ญํ ๋ง ํ๋๋ก ์ฌ์ฉํ์๋ค.
Dish ํด๋์ค ๋ฆฌ์คํธ์์ 1000 ์นผ๋ก๋ฆฌ ์ดํ์ ์๋ฆฌ๋ง ๊ณจ๋ผ์, ์นผ๋ก๋ฆฌ๋ก ์ ๋ ฌ์ ํ์ฌ ์ด๋ฆ์ ์ป๊ณ ์ถ์ ๋ฟ์ธ๋ฐ, ๊ฐ๋น์ง ๋ณ์๋ก ์ธํด ๋นํจ์จ์ ์ผ๋ก ๋ณด์ธ๋ค.
์คํธ๋ฆผ์ผ๋ก ๋ฐ๊พธ๊ฒ ๋๋ฉด ์๋ ๊ฒ ํ ์ ์๋ค.
@Test
@DisplayName("์๋ฆฌ ํด๋์ค๋ฅผ ์คํธ๋ฆผ์ผ๋ก ์ ๋ ฌํ๊ธฐ")
void sortStreamExample() {
List<String> lowCalDishesName = menuList.stream()
.filter(dish -> dish.getCalories() < 1000)
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)
.collect(Collectors.toList());
}
ํ ์ค๋ง ๋ฐ๊พธ๊ธฐ
@Test
@DisplayName("์๋ฆฌ ํด๋์ค๋ฅผ parallel ์คํธ๋ฆผ์ผ๋ก ์ ๋ ฌํ๊ธฐ")
void parallelStreamExample() {
List<String> lowCalDishesName = menuList.parallelStream()
.filter(dish -> dish.getCalories() < 1000)
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)
.collect(Collectors.toList());
}
stream()๋ฅผ parallelStream()๋ก ๋ฐ๊พธ๋ฉด ๋ฉํฐ์ฝ์ด ์ํคํ ์ณ์์ ๋ณ๋ ฌ๋ก ์คํํ ์ ์๋ค.
??
๋ง์ ํ์ด์ ์ค๋ช ํ์๋ฉด,
stream()
์ parallelStream()
๋ Java์ ์คํธ๋ฆผ API์์ ์ ๊ณตํ๋ ๋ ๊ฐ์ง ๋ฉ์๋์ธ๋ฐ, ์ด๋ค์ ์ปฌ๋ ์
(์: ๋ฆฌ์คํธ, ์ธํธ, ๋งต ๋ฑ)์ ๋ํด ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ์ํํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
stream()
๋ฉ์๋:stream()
๋ฉ์๋๋ ์์๋ฅผ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ์คํธ๋ฆผ์ ์์ฑ- ์์ฐจ ์คํธ๋ฆผ์ ๋จ์ผ ์ค๋ ๋์์ ์์ ์ ์ํํ๋ฉฐ, ๊ฐ ์์๋ ์ด์ ์์์ ์ฒ๋ฆฌ๊ฐ ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆผ
List<Integer> myList = Arrays.asList(1, 2, 3, 4, 5); // ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌ myList.stream().forEach(System.out::println);
parallelStream()
๋ฉ์๋:parallelStream()
๋ฉ์๋๋ ์ฌ๋ฌ ์ค๋ ๋์์ ๋์์ ์์๋ฅผ ์ฒ๋ฆฌํ๋ ๋ณ๋ ฌ ์คํธ๋ฆผ์ ์์ฑ- ๋ณ๋ ฌ ์คํธ๋ฆผ์ ๋ฉํฐ์ฝ์ด ์ํคํ ์ฒ์์ ๋์์ ์ฌ๋ฌ ์์ ์ ์ํํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์
List<Integer> myList = Arrays.asList(1, 2, 3, 4, 5); // ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌ myList.parallelStream().forEach(System.out::println);
๋ฐ๋ผ์ "stream()๋ฅผ parallelStream()์ผ๋ก ๋ฐ๊พธ๋ฉด ๋ฉํฐ์ฝ์ด ์ํคํ
์ฒ์์ ๋ณ๋ ฌ๋ก ์คํํ ์ ์๋ค"๋ ๋ง์, ์์ฐจ์ ์ธ ์ฒ๋ฆฌ์์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌ๋ก ์ ํํ๋ฉด ๋ฉํฐ์ฝ์ด ์์คํ
์์ ๋์์ ์ฌ๋ฌ ์์
์ ์ํํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
(๋ณ๋ ฌ์ฒ๋ฆฌ๊ฐ ๋ฌด์กฐ๊ฑด ์ฑ๋ฅ์ด ์ข์ ๊ฒ์ ์๋ฏธํ๋ ๊ฒ์ ์๋)
parallelStream() ํธ์ถํด์ ์ข์ ์
- ์ ์ธํ์ผ๋ก ์ฝ๋๋ฅผ ๊ตฌํ ๊ฐ๋ฅํ๋ค.
- if ๋ฌธ์ฒ๋ผ ์ ์ด ๋ธ๋ก์ ์ฌ์ฉํ์ง ์๊ณ '1000 ๋ณด๋ค ๋ฎ์ ์นผ๋ก๋ฆฌ์ ์๋ฆฌ๋ง ์ ํ' ์ด๋ผ๋ ๋์๋ง ์ํํ ์ ์๊ฒ ํ ์ ์๋ค.
- ์ฌ๋ฌ ๋น๋ฉ ๋ธ๋ก ์ฐ์ฐ์ ์ฐ๊ฒฐํด์ ๋ณต์ํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ์ ๋ง๋ค ์ ์๋ค.
filter, sorted, map, collect
์ฐ์ฐ์ ๊ณ ์์ค ๋น๋ฉ ๋ธ๋ก(high-level building block)์ผ๋ก ์ด๋ฃจ์ด์ ธ ์์ด์ ํน์ ์ค๋ ๋ฉ ๋ชจ๋ธ์ ์๊ด ์์ด ํฌ๋ช
ํ๊ฒ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค. ๋จ์ผ ์ค๋ ๋์์๋ ์ฌ์ฉ ๊ฐ๋ฅํ์ง๋ง ๋ฉํฐ ์ค๋ ๋ฉ์ ๋ ํ์ฉํ๋๊ฒ ์ข๋ค.
๊ทธ๋ฆฌ๊ณ , ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ณผ์ ์ด ๋ณ๋ ฌํ๋๋ค๋๊ฑด!! ์ค๋ ๋์ ๋ฝ์ ๋ฐ๋ก ๊ตฌํํ ํ์๊ฐ ์๋ค... ๋๋ฌด ์ข์๋ฐ?
์คํธ๋ฆผ API ํน์ง
- ์ ์ธํ: ๋ ๊ฐ๊ฒฐํ๊ณ ๊ฐ๋ ์ฑ์ด ์ข๋ค
- ์กฐ๋ฆฝํ ์ ์๋ค
- ์ ์ฐํ๋ค
- ๋ณ๋ ฌํ๊ฐ ๊ฐ๋ฅํ์ฌ ์ฑ๋ฅ์ด ์ข์์ง๋ค
์คํธ๋ฆผ ์์ํ๊ธฐ
์๋ฐ 8 ์ปฌ๋ ์ ์ ์ถ๊ฐ๋ ์คํธ๋ฆผ์ ๋ฐํํ๋ stream()์ ์์๋ณด์
์คํธ๋ฆผ ์ ์
๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฐ์ฐ์ ์ง์ํ๋๋ก ์์ค์์ ์ถ์ถ๋ ์ฐ์๋ ์์
- ์ฐ์๋ ์์
ํน์ ์์ ํ์์ผ๋ก ์ด๋ค์ง ์ฐ์๋ ๊ฐ ์งํฉ์ ์ธํฐํ์ด์ค ์ ๊ณต.
- ์ปฌ๋ ์ : ๋ฐ์ดํฐ๋ฅผ ์ฃผ์ ๋ก, ์๊ฐ๊ณผ ๊ณต๊ฐ์ ๋ณต์ก์ฑ๊ณผ ๊ด๋ จ๋ ์ฐ์ฐ ์ ์ฃผ๋ก ์ฌ์ฉํ๋ค.
- ์คํธ๋ฆผ: ๊ณ์ฐ์ ์ฃผ์ ๋ก, ๊ณ์ฐ์์ ์ฃผ๋ก ์ฌ์ฉ๋๋ค. (filter, sorted, map ๋ฑ)
- ์์ค
์ปฌ๋ ์ , ๋ฐฐ์ด, I/O ๋ฐ์ดํฐ ์ ๊ณต ์์ค๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์๋นํ๋ค.
์ ๋ ฌ๋ ์์ค๋ก ์คํธ๋ฆผ์ ๋ง๋ค๋ฉด ๊ฐ์ ๋ฐ์ดํฐ ์์๋ฅผ ์ ์งํ๋ค.
์๋ฅผ ๋ค์ด ๋ฆฌ์คํธ๋ก ์คํธ๋ฆผ์ ๋ง๋ค๋ฉด ์์์ ์์๋ ๋ฆฌ์คํธ์ ์์์ ๊ฐ๋ค.
- ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฐ์ฐ
ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋น์ทํ ์ฐ์ฐ์ ์ง์ํ๋ค.
์์ฐจ์ /๋ณ๋ ฌ๋ก ์คํธ๋ฆผ ์ฐ์ฐ์ ์คํํ ์ ์๋ค.
์คํธ๋ฆผ ์ฃผ์ ํน์ง
- Pipelining
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ง์๋ฅผ ํ๋ ๊ฒ ์ฒ๋ผ, ์คํธ๋ฆผ ์ฐ์ฐ์ ์ฐ๊ฒฐํด์ ์ปค๋ค๋ ํ์ดํ ํํ๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํด ์คํธ๋ฆผ ์์ ์ ๋ฐํํ๋ค.
laziness, short-circuiting ๊ฐ์ ์ต์ ํ๋ฅผ ์ป์ ์ ์๋ค ํจ.
- ๋ด๋ถ ๋ฐ๋ณต
- ์ปฌ๋ ์ : ๋ฐ๋ณต์๋ฅผ ์ด์ฉํด์ ๋ช ์์ ์ธ ๋ฐ๋ณต
- ์คํธ๋ฆผ ๋ด๋ถ ๋ฐ๋ณต์ ์ง์
์คํธ๋ฆผ ์์
List<Dish> menuList = new ArrayList<>();
@BeforeEach
void setUp() {
menuList.add(new Dish(100, "๋ญ๊ฐ์ด์ด", false, Type.MEAT));
menuList.add(new Dish(1500, "์นํจ", false, Type.MEAT));
menuList.add(new Dish(500, "์คํ", false, Type.OTHER));
menuList.add(new Dish(50, "์ผ์ฑ๋ณถ์", true, Type.OTHER));
}
//
@Test
@DisplayName("์๋ฆฌ ํด๋์ค๋ฅผ ์คํธ๋ฆผ์ผ๋ก ์ ๋ ฌํ๊ธฐ")
void sortStreamExample() {
List<String> lowCalDishesName = menuList.stream()// menuList์์ ์คํธ๋ฆผ์ ์ป์ด์ด
.filter(dish -> dish.getCalories() < 1000)// ํ์ดํ๋ผ์ธ ์ฐ์ฐ์ ๋ง๋ฆ. 1000์นผ๋ก๋ฆฌ๋ณด๋ค ์ ์ ์๋ฆฌ๋ฅผ ํํฐ๋ง ํ๋ค.
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)// ์๋ฆฌ ์ด๋ฆ์ ๊ฐ์ ธ์จ๋ค
.limit(2)
.collect(Collectors.toList()); // ์คํธ๋ฆผ ๊ฒฐ๊ณผ๋ฅผ ๋ค๋ฅธ ๋ฆฌ์คํธ๋ก ์ ์ฅํ๋ค๋ ๋ป์ด์์ด~
}
- ๋ฐ์ดํฐ ์์ค
์์์, ์คํธ๋ฆผ์ ์ ์์์ '์์ค'๋ผ๋ ์ฉ์ด๊ฐ ๋์๋๋ฐ, ์ด๋ ๋ฐ์ดํฐ ์์ค๋ฅผ ์๋ฏธํ๋ค.
์์ ์์์ ๋ฐ์ดํฐ ์์ค๋ menuList์ด๋ค.
๋ฐ์ดํฐ ์์ค๋ ์ฐ์๋ ์์๋ฅผ ์คํธ๋ฆผ์๊ฒ ์ ๊ณตํ๋ค.
- ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฐ์ฐ
์คํธ๋ฆผ์ filter, map, limit, collect ๊ฐ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฐ์ฐ์ ์ ์ฉํ ์ ์๋ค.
1) filter
๋๋ค๋ฅผ ์ธ์๋ก ๋ฐ์, ์คํธ๋ฆผ์์ ํน์ ์์๋ฅผ ํํฐ๋งํ๋ค. ์๋ฅผ ๋ค์ด 1000์นผ๋ก๋ฆฌ๋ณด๋ค ์ ์ ๋ฐ์ดํฐ๋ง ์ ํํ๊ณ , ๋๋จธ์ง๋ ์ ์ธ์์ผฐ๋ค.
2) map
๋๋ค๋ฅผ ์ด์ฉํด์ ๋ค๋ฅธ ์์๋ก ๋ฐ๊พธ๊ฑฐ๋ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์จ๋ค. ์๋ฅผ ๋ค์ด ๋ฉ๋ด์ ์ด๋ฆ์ ๊ฐ์ ธ์ค๋ ์.
3) limit
์ ํด์ง ๊ฐ์ ์ด์์ ์์๊ฐ ์คํธ๋ฆผ์ ์ ์ฅ ์๋๋๋ก ์คํธ๋ฆผ ํฌ๊ธฐ๋ฅผ ์ค์๋ค.
4) collect
๋ค๋ฅธ ํ์์ผ๋ก ๋ณํํ๋ค. ์๋ฅผ ๋ค์ด ๋ฆฌ์คํธ๋ก ๋ฐํํ๋ ์.
filter, map, limit ์ฐ์ฐ์ ์๋ก ํ์ดํ๋ผ์ธ์ ํ์ฑ ํ ์ ์๋๋ก ์คํธ๋ฆผ์ ๋ฐํํ์ง๋ง, collect๋ ํ์ดํ๋ผ์ธ์ ์ฒ๋ฆฌํด์ ๋ค๋ฅธ ํํ๋ฆ ๊ฒฐ๊ณผ๋ก ๋ฐํํ๋ค.
collect๋ฅผ ํธ์ถํด์ผ ์ถ๋ ฅ ๊ฒฐ๊ณผ๊ฐ ์๋ค.
limit๋ก ์์๋ฅผ ์ ์ธ ์์ผ๋, ์คํธ๋ฆผ ์ถ๋ ฅ ๊ฒฐ๊ณผ์ ์ํฅ์ ์๋ค.
์คํธ๋ฆผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด, ํํฐ๋ง/์ถ์ถ/์ถ์ ๊ธฐ๋ฅ์ ์ง์ ๊ตฌํํ์ง ์๊ณ ๋ ํ์ดํ๋ผ์ธ์ ๋ ์ต์ ํ ํ ์ ์๋ ์ ์ฐ์ฑ์ ๊ฐ์ง ์ ์๋ค.
์คํธ๋ฆผ๊ณผ ์ปฌ๋ ์
์ปฌ๋ ์ ๊ณผ ์คํธ๋ฆผ์ ๊ณตํต์ ์ ์ฐ์๋ ์์ ํ์์ ๊ฐ์ ์ ์ฅํ๋ ์๋ฃ๊ตฌ์กฐ์ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค๋ ์ ์ด๋ค.
์ฐ์๋๋ค๋ผ๋ ๊ฑด ์์ฐจ์ ์ผ๋ก ๊ฐ์ ์ ๊ทผํ๋ค๋ ๊ฒ์ด๋ค.
๊ทธ๋ฌ๋ฉด ์ฐจ์ด์ ์ ๋ฌด์์ผ๊น๋
์คํธ๋ฆผ๊ณผ ์ปฌ๋ ์ ์ ์ฐจ์ด์ 1: ๋ฐ์ดํฐ๋ฅผ ์ธ์ ๊ณ์ฐํ๋๊ฐ?
๋ทํ๋ฆญ์ค๋ ์ ํ๋ธ๋ฅผ ๋ณผ ๋ ์คํธ๋ฆฌ๋ฐ ์๋น์ค๋ฅผ ๋ณธ๋ค๊ณ ์๊ธฐ๋ฅผ ํ๋ค.
๊ทธ ๋ ๊ทธ ์คํธ๋ฆฌ๋ฐ์ด ์คํธ๋ฆผ์ด๋ค.
์์ ๋ฐ์ดํฐ๋ฅผ ์ฒ์๋ถํฐ ์ฌ์ํ ๋, ๋ค์๋ ์์ง ๋ค ๋ด๋ ค ๋ฐ์ง๋ ์์์ง๋ง ๋ฏธ๋ฆฌ ๋ฐ์ ์์ชฝ ํ๋ ์๋ถํฐ ์ฌ์์ด ๊ฐ๋ฅํ๋ค.
๋ง์ฝ 3์๊ฐ์ง๋ฆฌ ์ํ๋ฅผ ์ฒ์๋ถํฐ ๋ค์ด๋ก๋ํ๊ณ ๋ดค๋ค๋ฉด ์คํธ๋ฆฌ๋ฐ ๋ณด๋ค๋ ์๊ฐ์ด ์กฐ๊ธ ๋ ๊ฑธ๋ฆด ๊ฒ์ด๋ค.
์ปฌ๋ ์
ํ์ฌ ์๋ฃ๊ตฌ์กฐ๊ฐ ํฌํจํ๋ ๋ชจ๋ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ ์๋ฃ๊ตฌ์กฐ.
์ปฌ๋ ์ ์ ์ถ๊ฐ๋๊ธฐ ์ ์ ๋ชจ๋ ์์๊ฐ ๊ณ์ฐ๋์ด์ผ ํ๋ค.
์ปฌ๋ ์ ์ ์์๋ฅผ ์ถ๊ฐ/์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค.
์คํธ๋ฆผ
์์ฒญํ ๋๋ง ์์๋ฅผ ๊ณ์ฐํ๋ ๊ณ ์ ๋ ์๋ฃ๊ตฌ์กฐ.
์คํธ๋ฆผ์ ์์๋ฅผ ์ถ๊ฐ/์ญ์ ํ ์ ์๋ค.
์คํธ๋ฆผ์์๋ ์์ฐ์์ ์๋น์๋ผ๋ ์ฉ์ด๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์ฌ์ฉ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ ๋๋ง ๊ทธ ๋ ๋ฐ์ดํฐ ๊ฐ์ ๊ณ์ฐํ๋ค.
์ด๋ฌํ ์ ์ ๋ณด๊ณ ๊ฒ์ผ๋ฅด๋ค๊ณ ๋ง์ ํ๋ค.
์ปฌ๋ ์ ์ ๋ชจ๋ ๊ฑธ ๊ณ์ฐํด์ ์์ฐ์ ์ค์ฌ์ผ๋ก ์ฐฝ๊ณ ๋ฅผ ๋ค ์ฑ์ ๋๋ ์คํ์ผ์ด๋ค.
์๋น์๋ ๋ช๊ฐ ๋ฐ์ ์ ํ์ํ๋ฐ๋ ๋ง์ด๋ค. ๋ถ์ง๋ฐํ๋ค. ํ์ง๋ง ์๋น์๋ ํ์ผ์์ด ์ฐฝ๊ณ ์ ๋ด์ฉ์ ๋ด์ผํ๋ค.
๋ฑ ํ๋ฒ๋ง ํ์ํ ์ ์๋ค
๋ฐ๋ณต์์ฒ๋ผ ์คํธ๋ฆผ๋ ํ๋ฒ๋ง ํ์์ด ๊ฐ๋ฅํ๋ค. ๋ฐ์ดํฐ ์์๋ ํ ๋ฒ ํ์๋๋ฉด ์๋น๋๋ค.
@Test
void streamOneChance() {
List<String> idols = Arrays.asList("์์ด์ ", "์์คํ", "๋ฅด์ธ๋ผํ");
Stream<String> stream = idols.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println); // Error! stream has already been operated upon or closed
}
ํ
์คํธ ์์ ๋ฅผ ์์ฑํด๋ณด๋ฉด, ๋ง์ง๋ง ์ค์์ ์คํธ๋ฆผ์ ํ๋ฒ๋ ์ถ๋ ฅํ๋ ค๊ณ ํ๋, stream has already been operated upon or closed
๋ผ๋ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒ์ ๋ณผ ์ ์๋ค.
์คํธ๋ฆผ๊ณผ ์ปฌ๋ ์ ์ ์ฐจ์ด์ 2: ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ๋ฐ๋ณต ์ฒ๋ฆฌํ๋๊ฐ?
์ปฌ๋ ์ ์ธํฐํ์ด์ค๋ ์ฌ์ฉ์๊ฐ for-each ๊ฐ์ ๊ฑธ ์ฌ์ฉํด์ ์ง์ ๋ฐ์ดํฐ ์์๋ฅผ ๋ฐ๋ณตํด์ผํ๋ค.
์ด๋ฅผ ์ธ๋ถ ๋ฐ๋ณต์ด๋ผ๊ณ ํจ.
๋ด๋ถ ๋ฐ๋ณต์, ์คํธ๋ฆผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ฒ๋ผ ๋ฐ๋ณต์ ์์์ ๋ค ํ๊ณ ์ด๋๊ฐ์ ์ ์ฅ๋ ํด์ฃผ๋ ๊ฒ์ด๋ค.
@Test
void iteratorTest() {
List<String> idols = Arrays.asList("์์ด์ ", "์์คํ", "๋ฅด์ธ๋ผํ");
// 1. ์ธ๋ถ ๋ฐ๋ณต
List<String> photo = new ArrayList<>();
Iterator<String> iterator = idols.iterator();
while (iterator.hasNext()) {
photo.add(iterator.next());
}
// 2. ๋ด๋ถ ๋ฐ๋ณต
List<String> photo2 = idols.stream()
.collect(Collectors.toList());
}
๋ด๋ถ ๋ฐ๋ณต์ ํ๋ฉด ๋ญ๊ฐ ์ข์ผ๋.
์์ ์ ํฌ๋ช ํ๊ฒ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ์ฌ ๋ ์ต์ ํํด์ ๋ค์ํ ์์๋ก ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
๋ฐ์ดํฐ ํํ๊ณผ ํ๋์จ์ด๋ฅผ ํ์ฉํ ๋ณ๋ ฌ์ฑ ๊ตฌํ์ ์๋์ผ๋ก ์ ํํ๋ค.
๋ณ๋ ฌ์ฑ์ ์์์ ํด์ฃผ๊ธฐ ๋๋ฌธ์, ๋ฝ์ด๋ ๋๊ธฐํ ๋ฌธ์ ๋ฑ์ ๊ด๋ฆฌํ์ง ์์๋ ๋๋ค.
์ฑ ์์ ๊ฐ ์ธ์ ๊น์๋๋ฐ,
์์ด์๊ฒ ๋ฐ๋ฅ์ ๋จ์ด์ง ์ฅ๋๊ฐ์ ํ๋ ํ๋ ๋งํด์ฃผ๋ฉด์, ๊ทธ ๋ค์์ ์ด๊ฑฐ ์ ๋ฆฌํด. ์ด๊ฑฐ ์ ๋ฆฌํด. ํ๋๊ฑฐ๋ณด๋ค๋
์์ด๊ฐ ํ๋ฒ์ ์ ๋ฆฌํด์ ์ฅ๋๊ฐ ์์๋ฅผ ์ฃผ๋ฉด ์ผ๋ง๋ ์ข์๊น์ ๋ํ ์์ ๊ฐ ์์๋ค.
๊ทธ๋ฌ๋ฉด ๋ ์์ผ๋ก ํ๋ฒ์ ์ ๋ฆฌ๋ฅผ ํ๊ธฐ๋ ํ๊ณ ์๊ฐ๋ ๋จ์ถ๋๋๊น, ๋ด๋ถ ๋ฐ๋ณต์ด ๋ ์ข๋ค๋..
์คํธ๋ฆผ ์ฐ์ฐ
์คํธ๋ฆผ์ ๋ด๋ถ ๋ฐ๋ณต์ ์ ๊ฒฝ์ ์์จ๋ ๋๋ค๋ ๊ฒ์, ๋ฐ์ดํฐ ์ฐ์ฐ ๋ฆฌ์คํธ๊ฐ ๋ฏธ๋ฆฌ ์ ์ ๋์ด์ผํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
์์ด๊ฐ ์ฅ๋๊ฐ์ ์ ๋ฆฌํ ์ ์๋ ์๊ณ ๋ฆฌ์ฆ์ด๋๊น?
๊ทธ ์ฐ์ฐ์ ๋๋ค ํํ์์ผ๋ก ์ธ์๋ก ๋ฐ๊ณ , ๋์ ํ๋ผ๋ฏธํฐํ๋ ํ์ฉ์ด ๊ฐ๋ฅํ๋ค.
@Test
@DisplayName("์๋ฆฌ ํด๋์ค๋ฅผ ์คํธ๋ฆผ์ผ๋ก ์ ๋ ฌํ๊ธฐ")
void sortStreamExample() {
List<String> lowCalDishesName = menuList.stream()// menuList์์ ์คํธ๋ฆผ์ ์ป์ด์ด
.filter(dish -> dish.getCalories() < 1000)// ํ์ดํ๋ผ์ธ ์ฐ์ฐ์ ๋ง๋ฆ. 1000์นผ๋ก๋ฆฌ๋ณด๋ค ์ ์ ์๋ฆฌ๋ฅผ ํํฐ๋ง ํ๋ค.
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)// ์๋ฆฌ ์ด๋ฆ์ ๊ฐ์ ธ์จ๋ค
.limit(2)
.collect(Collectors.toList()); // ์คํธ๋ฆผ ๊ฒฐ๊ณผ๋ฅผ ๋ค๋ฅธ ๋ฆฌ์คํธ๋ก ์ ์ฅํ๋ค๋ ๋ป์ด์์ด~
}
์๊น ๋ดค๋ ์์ ๋ฅผ ํ ๋ฒ ๋ ๊ฐ์ ธ์๋ค.
์ด๋ฅผ ๋ ๋ถ๋ถ์ผ๋ก ๋๋ ์ ์๋ค.
- filter, map, limit์ ์๋ก ์ฐ๊ฒฐ๋์ด ํ์ดํ๋ผ์ธ์ ํ์ฑ
- collect๋ก ํ์ดํ๋ผ์ธ์ ์คํ ํ ์คํธ๋ฆผ์ ๋ซ๋๋ค.
filter, map, limit ๊ฐ์ ์ฐ์ฐ์ ์ค๊ฐ ์ฐ์ฐ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
collect ๊ฐ์ด ์คํธ๋ฆผ์ ๋ซ๋ ์ฐ์ฐ์ ์ต์ข
์ฐ์ฐ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์ค๊ฐ ์ฐ์ฐ (intermediate operation)
filter, sorted ๊ฐ์ ์ค๊ฐ ์ฐ์ฐ์ด ํ์ดํ๋ผ์ธ์ผ๋ก ์ฐ๊ฒฐ๋๋ค๋ ๊ฒ์, ๊ฐ๊ฐ ๋ค๋ฅธ ์คํธ๋ฆผ์ ๋ฐํํ๊ณ ์ด ๊ฐ๊ฐ์ ์คํธ๋ฆผ์ด ์ฐ๊ฒฐ๋์ด ํ์ดํ๋ผ์ธ์ ํ์ฑํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
๋จ๋ง ์ฐ์ฐ์ด ํ์ดํ๋ผ์ธํ ๋๋ ๊ฒ์ด๋ค.
๋จ๋ง ์ฐ์ฐ์ ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ์คํ๋๊ธฐ ์ ์๋ ์๋ฌด๊ฒ๋ ์ํ๋ค๊ฐ(๊ฒ์ผ๋ฆ), ์ค๊ฐ ์ฐ์ฐ์ ํฉ์น ๋ค์์ ์ต์ข ์ฐ์ฐ์ผ๋ก ํ๋ฒ์ ์ฒ๋ฆฌํ๋ค.
@Test
@DisplayName("์๋ฆฌ ํด๋์ค๋ฅผ ์คํธ๋ฆผ์ผ๋ก ์ ๋ ฌํ๊ธฐ")
void shortCircuit() {
List<String> lowCalDishesName = menuList.stream()
.filter(dish -> {
System.out.println("filtering:"+dish.getName());
return dish.getCalories() < 1000;
})
.map( dish -> {
System.out.println("mapping:"+dish.getName());
return dish.getName();
})
.limit(2)
.collect(Collectors.toList());
System.out.println("results:"+ lowCalDishesName);
}
์ ์์ ๋ฅผ ์คํ์์ผ๋ณด๋ฉด ์๋์ ๊ฐ์ด ์ถ๋ ฅ๋๋ค.
filtering:๋ญ๊ฐ์ด์ด
mapping:๋ญ๊ฐ์ด์ด
filtering:์คํ
mapping:์คํ
results:[๋ญ๊ฐ์ด์ด, ์คํ]
์ด ์ฒ๋ผ, filter์ map์ ์๋ก ๋ค๋ฅธ ์ฐ์ฐ์ด์ง๋ง, ํ์ดํ๋ผ์ธํ๊ฐ ๋์ด ํ ๊ณผ์ ์ผ๋ก ๋ณํฉ๋ ๊ฒ์ ์ ์ ์๋ค. (๋ฃจํ ํจ์ )
์ค๊ฐ ์ฐ์ฐ ์ข ๋ฅ
- filter
- map
- limit
- sorted
- distinct
์ต์ข ์ฐ์ฐ (terminal operation)
์ต์ข ์ฐ์ฐ์ ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์์ ๊ฒฐ๊ณผ๋ฅผ ๋์ถํ๋ ์ญํ ์ด๋ค.
List, Integer, void ๊ฐ์ ์คํธ๋ฆผ ์ด์ธ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ์ฌ ์ฌ์ฉํ๋ค.
@Test
void streamExample() {
menuList.stream().forEach(System.out::println);
}
forEach๋ System.out::println ๋๋ค๋ฅผ ์ ์ฉํด์ void๋ก ๋ฐํํ๋ ์ต์ข ์ฐ์ฐ์ผ๋ก ์ฐ์๋ค.
์ต์ข ์ฐ์ฐ ์ข ๋ฅ
- forEach: ์คํธ๋ฆผ์ ๊ฐ ์์๋ฅผ ์๋นํ๋ฉด์ ๋๋ค๋ฅผ ์ ์ฉํ๊ธฐ ์ํด ์ฌ์ฉ
- count: ์คํธ๋ฆผ์ ์์ ๊ฐ์๋ฅผ ๋ฐํํจ
- collect: ์คํธ๋ฆผ์ผ๋ก List, Map, ์ ์ํ์์ ์ปฌ๋ ์ ์ ์์ฑํ๊ธฐ ์ํด ์ฌ์ฉํจ
์คํธ๋ฆผ ์ด์ฉ ๊ณผ์
- ์ง์๋ฅผ ์ํํ ๋ฐ์ดํฐ ์์ค (์ปฌ๋ ์ )
- ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ ์ค๊ฐ ์ฐ์ฐ ์ฐ๊ฒฐ (filter, map ๋ฑ)
- ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค ์ต์ข ์ฐ์ฐ (collect ๋ฑ)
์ ๋ฆฌ
- ์คํธ๋ฆผ์ ๋ฐ์ดํฐ ์์ค์์ ์ถ์ถ๋ ์ฐ์ ์์๋ก ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฐ์ฐ์ ์ง์
- ๋ด๋ถ ๋ฐ๋ณต์ ์ง์
- ์ค๊ฐ ์ฐ์ฐ๊ณผ ์ต์ข ์ฐ์ฐ์ผ๋ก ๊ตฌ์ฑ
- ์ค๊ฐ ์ฐ์ฐ: ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ์ง๋ง ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ ์๋ ์๋ ์ฐ์ฐ
- ์ต์ข ์ฐ์ฐ: ์คํธ๋ฆผ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ์ฐ์ฐ
'๐ Java&Spring > ๋ชจ๋์๋ฐ์ธ์ก์ ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋ชจ๋์๋ฐ์ธ์ก์ ] Stream ์คํธ๋ฆผ ํ์ฉ (4) | 2024.03.26 |
---|---|
[๋ชจ๋์๋ฐ์ธ์ก์ ] ๋๋ค (Lambda) (4) | 2023.12.03 |
[๋ชจ๋์๋ฐ์ธ์ก์ ] ๋์ ํ๋ผ๋ฏธํฐ(Behavior Parameter) (4) | 2023.11.19 |