Skip to main content

Part 2-1 ํ•จ์ˆ˜ํ˜• ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ

2023๋…„ 12์›” 27์ผAbout 5 minJavacrashcoursejavajdkjdk8

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๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „๊นŒ์ง€ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด ์ €์žฅ๋˜๋Š” ํšจ๊ณผ๊ฐ€ ์žˆ๋‹ค.

a
a

์ŠคํŠธ๋ฆผ๊ณผ ์ปฌ๋ ‰์…˜

์ž๋ฐ”์˜ ๊ธฐ์กด ์ปฌ๋ ‰์…˜๊ณผ ์ƒˆ๋กœ์šด ์ŠคํŠธ๋ฆผ ๋ชจ๋‘ ์—ฐ์†๋œ ์š”์†Œ ํ˜•์‹์˜ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ โ€˜์—ฐ์†๋œโ€™์ด๋ผ๋Š” ํ‘œํ˜„์€ ์ˆœ์„œ์™€ ์ƒ๊ด€์—†์ด ์•„๋ฌด ๊ฐ’์—๋‚˜ ์ ‘์† ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ˆœ์ฐจ์ ์œผ๋กœ ๊ฐ’์— ์ ‘๊ทผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์ด์ œ ์ปฌ๋ ‰์…˜๊ณผ ์ŠคํŠธ๋ฆผ์˜ ์ฐจ์ด๋ฅผ ์‚ดํŽด๋ณด์ž.

๋ฐ์ดํ„ฐ๋ฅผ ์–ธ์ œ ๊ณ„์‚ฐํ•˜๋А๋ƒ๊ฐ€ ์ปฌ๋ ‰์…˜๊ณผ ์ŠคํŠธ๋ฆผ์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ปฌ๋ ‰์…˜์€ ํ˜„์žฌ ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ํฌํ•จํ•˜๋Š” ๋ชจ๋“  ๊ฐ’์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋‹ค. ์ฆ‰, ์ปฌ๋ ‰์…˜์˜ ๋ชจ๋“  ์š”์†Œ๋Š” ์ปฌ๋ ‰์…˜์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „์— ๊ณ„์‚ฐ๋˜์–ด์•ผ ํ•œ๋‹ค(์ปฌ๋ ‰์…˜์— ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ปฌ๋ ‰์…˜์˜ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฐ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ์ปฌ๋ ‰์…˜์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•ด์•ผ ํ•˜๋ฉฐ ์ปฌ๋ ‰์…˜์— ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ์š”์†Œ๋Š” ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ๋˜์–ด์•ผ ํ•œ๋‹ค).

๋ฐ˜๋ฉด ์ŠคํŠธ๋ฆผ์€ ์ด๋ก ์ ์œผ๋กœ ์š”์ฒญํ•  ๋•Œ๋งŒ ์š”์†Œ๋ฅผ ๊ณ„์‚ฐ ํ•˜๋Š” ๊ณ ์ •๋œ ์ž๋ฃŒ๊ตฌ์กฐ๋‹ค(์ŠคํŠธ๋ฆผ์— ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ŠคํŠธ๋ฆผ์—์„œ ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์—†๋‹ค). ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•˜๋Š” ๊ฐ’๋งŒ ์ŠคํŠธ๋ฆผ์—์„œ ์ถ”์ถœํ•œ๋‹ค๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ด๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ŠคํŠธ๋ฆผ์€ ์ƒ์‚ฐ์ž์™€ ์†Œ๋น„์ž ๊ด€๊ณ„๋ฅผ ํ˜•์„ฑํ•œ๋‹ค. ๋˜ํ•œ ์ŠคํŠธ๋ฆผ์€ ๊ฒŒ์œผ๋ฅด๊ฒŒ ๋งŒ๋“ค์–ด์ง€๋Š” ์ปฌ๋ ‰์…˜๊ณผ ๊ฐ™๋‹ค. ์ฆ‰, ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•  ๋•Œ๋งŒ ๊ฐ’์„ ๊ณ„์‚ฐํ•œ๋‹ค. ๋ฐ˜๋ฉด ์ปฌ๋ ‰์…˜์€ ์ ๊ทน์ ์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค(์ƒ์‚ฐ์ž ์ค‘์‹ฌ: ํŒ”๊ธฐ๋„ ์ „์— ์ฐฝ๊ณ ๋ฅผ ๊ฐ€๋“ ์ฑ„์›€). ์†Œ์ˆ˜ ์˜ˆ์ œ๋ฅผ ์ ์šฉํ•ด๋ณด๋ฉด ์ปฌ๋ ‰์…˜์€ ๋์ด ์—†๋Š” ๋ชจ๋“  ์†Œ์ˆ˜๋ฅผ ํฌํ•จํ•˜๋ ค ํ•  ๊ฒƒ์ด๋ฏ€๋กœ ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ ์ƒˆ๋กœ์šด ์†Œ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ์ถ”๊ฐ€ํ•˜๊ธฐ๋ฅผ ๋ฐ˜๋ณตํ•  ๊ฒƒ์ด๋‹ค. ๊ฒฐ๊ตญ ์†Œ๋น„์ž๋Š” ์˜์›ํžˆ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค.

์ŠคํŠธ๋ฆผ์€ ๋‹จ ํ•œ๋ฒˆ๋งŒ ์†Œ๋น„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

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>๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„์„œ ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ƒ์‚ฐํ•œ๋‹ค.