Skip to content

Latest commit

ย 

History

History
479 lines (347 loc) ยท 24.3 KB

File metadata and controls

479 lines (347 loc) ยท 24.3 KB

item 46 : ์ŠคํŠธ๋ฆผ์—์„œ๋Š” ๋ถ€์ž‘์šฉ ์—†๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

1. ์ŠคํŠธ๋ฆผ์˜ ํ•ต์‹ฌ : ์ŠคํŠธ๋ฆผ์„ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Œ

์ŠคํŠธ๋ฆผ์€ ๊ทธ์ € ๋˜ ํ•˜๋‚˜์˜ API๊ฐ€ ์•„๋‹Œ, ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๊ธฐ์ดˆํ•œ ํŒจ๋Ÿฌ๋‹ค์ž„์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ŠคํŠธ๋ฆผ์ด ์ œ๊ณตํ•˜๋Š” ํ‘œํ˜„๋ ฅ, ์†๋„, ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ๋Š” ๋ณ‘๋ ฌ์„ฑ์„ ์–ป์œผ๋ ค๋ฉด API๋Š” ๋งํ•  ๊ฒƒ ๋„ ์—†๊ณ  ์ด ํŒจ๋Ÿฌ๋‹ค์ž„๊นŒ์ง€ ํ•จ๊ป˜ ๋ฐ›์•„๋“ค์—ฌ์•ผ ํ•œ๋‹ค.

  • ์ŠคํŠธ๋ฆผ ํŒจ๋Ÿฌ๋‹ค์ž„์˜ ํ•ต์‹ฌ์€ ๊ณ„์‚ฐ์„ ์ผ๋ จ์˜ ๋ณ€ํ™˜(transformation)์œผ๋กœ ์žฌ๊ตฌ์„ฑ ํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.
  • ์ด๋•Œ ๊ฐ ๋ณ€ํ™˜ ๋‹จ๊ณ„๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ์ด์ „ ๋‹จ๊ณ„์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ ์ฒ˜ ๋ฆฌ ํ•˜๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜์—ฌ์•ผ ํ•œ๋‹ค.

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€?

{% hint style="info" %} ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ(functional programming)์€ ์ž๋ฃŒ ์ฒ˜๋ฆฌ๋ฅผ ํ•จ์ˆ˜์˜ ๊ณ„์‚ฐ์œผ๋กœ ์ทจ๊ธ‰ํ•˜๊ณ 
์ƒํƒœ์™€ ๊ฐ€๋ณ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ€๋ฆฌํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจ๋Ÿฌ๋‹ค์ž„ {% endhint %}

๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์›์‹œ์ ์ธ ๊ณ„์‚ฐ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ์ •ํ˜•ํ™”๋œ ํ•จ์ˆ˜๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์ƒํƒœ ๊ฐ’์ด๋‚˜ ๊ฐ€๋ณ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ€๋ฆฌํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š”๋ฐ ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜๋ฅผ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ผ๊ณ  ํ•œ๋‹ค.

์ˆœ์ˆ˜ํ•จ์ˆ˜๋ž€?

์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ž€ ์˜ค์ง ์ž…๋ ฅ๋งŒ์ด ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ํ•จ์ˆ˜ ์ฆ‰, ๋‹ค๋ฅธ ๊ฐ€๋ณ€ ์ƒํƒœ๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ณ , ํ•จ์ˆ˜ ์Šค์Šค๋กœ๋„ ๋‹ค๋ฅธ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋ฅผ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ผ ํ•œ๋‹ค.

์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ๊ฐ€๋ณ€ ๋ฐ ์ƒํƒœ ๊ฐ’์„ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ธฐ์— ์ž…๋ ฅ ๊ฐ’์— ์˜ํ•ด ๊ฒฐ๊ณผ ๊ฐ’์ด ์ •ํ•ด์ง€๋Š” ํŠน์„ฑ์„ ๊ฐ–๋Š”๋‹ค. ๋งŒ์•ฝ ์ƒํƒœ ๊ฐ’์„ ์ฐธ์กฐํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ์ž…๋ ฅ ๊ฐ’์— ์˜ํ•ด ๊ฒฐ๊ณผ ๊ฐ’์ด ๋‹ฌ๋ผ์ง€๋Š” '๋ถ€์ž‘์šฉ'์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๊ตญ ์ด๋ฒˆ ์ฃผ์ œ์ธ ๋ถ€์ž‘์šฉ ์—†๋Š” ํ•จ์ˆ˜๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ฅผ ๋งํ•œ๋‹ค.

์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ปค์Šคํ…€ํ•˜์—ฌ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ŠคํŠธ๋ฆผ API์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ŠคํŠธ๋ฆผ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ณต์‹์ ์ธ ํ•จ์ˆ˜์ด๋ฏ€๋กœ ๋ถ€์ž‘์šฉ์ด ์—†๊ณ , ์„ฑ๋Šฅ ์ตœ์ ํ™”๊ฐ€ ๋˜์–ด์žˆ์œผ๋ฉฐ, 40๊ฐ€์ง€ ์ด์ƒ์˜ ๋‹ค์–‘ํ•œ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋จผ์ € ์ŠคํŠธ๋ฆผ API๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ์ €์ž๋Š” ์ŠคํŠธ๋ฆผ ์ฝ”๋“œ๋ผ๊ณ  ์ธ์ •ํ•˜์ง€ ์•Š๋Š” ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

2. ์ŠคํŠธ๋ฆผ ํ•จ์ˆ˜์˜ ๋ณ€ํ™”

1) ๋‹จ์–ด ๋นˆ๋„ํ‘œ ์˜ˆ์ œ : ์‚ฌ์šฉ๋ฒ•๋งŒ ์•„๋Š” ๋‹จ๊ณ„

๋‹ค์Œ์€ ํ…์ŠคํŠธ ํŒŒ์ผ์—์„œ ๋‹จ์–ด๋ณ„ ์ˆ˜๋ฅผ ์„ธ์–ด ๋นˆ๋„ํ‘œ๋กœ ๋งŒ๋“œ๋Š” ์ฝ”๋“œ์ด๋‹ค. ์ŠคํŠธ๋ฆผ, ๋žŒ๋‹ค, ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ , ๊ฒฐ๊ณผ๋„ ์˜ฌ๋ฐ”๋ฅด์ง€๋งŒ ์ด๋ฅผ ์ŠคํŠธ๋ฆผ ์ฝ”๋“œ๋ผ ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ŠคํŠธ๋ฆผ์„ ์ž˜๋ชป ์‚ฌ์šฉํ–ˆ๊ณ , ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ๋ณด๋‹ค ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ŠคํŠธ๋ฆผ ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ์ƒํƒœ(freq)๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค. ์ด๋Š” ์ŠคํŠธ๋ฆผ์˜ ์ฃผ์š” ์„ค๊ณ„ ์ฒ ํ•™์ธ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ์–ด๊ธ‹๋‚œ๋‹ค. ์ŠคํŠธ๋ฆผ์€ ๋ฐ์ดํ„ฐ์˜ ๋ณ€ํ™˜(Transformation)๊ณผ ํ‰๊ฐ€(Evaluation)๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์ดˆ์ ์ด ๋งž์ถฐ์ ธ ์žˆ์œผ๋ฉฐ, ์™ธ๋ถ€ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ(Side-Effect)๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

@Test
public void wordFreq1Test() {
    List<String> words = Arrays.asList(
        "stop", "spot", "trim", "meet", 
        "ball", "free", "trim", "meet"
    );

    Map<String, Long> freq = new HashMap<>();

    // ๋ฌธ์ œ 1: ์™ธ๋ถ€ ์ƒํƒœ(freq)๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์ŠคํŠธ๋ฆผ ์‚ฌ์šฉ
    words.stream().forEach(
            word -> freq.merge(word.toLowerCase(), 1L, Long::sum) 
            // ์™ธ๋ถ€ ์ƒํƒœ(freq)๋ฅผ ๋ณ€๊ฒฝ -> ์ŠคํŠธ๋ฆผ์˜ ํ•จ์ˆ˜ํ˜• ํŒจ๋Ÿฌ๋‹ค์ž„์— ์œ„๋ฐฐ
    );

    System.out.println("words = " + words);
    System.out.println("freq = " + freq);
}
  • ์ŠคํŠธ๋ฆผ์˜ forEach() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•œ ์ฝ”๋“œ์ด๋‹ค.
  • ๋ฐฐ์—ด์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์—์„œ ์ถœ๋ฐœํ–ˆ์„ ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ, ์ผ๋ฐ˜์ ์œผ๋กœ Stream ๋ฃจํ”„์—์„œ ์™ธ๋ถ€ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ๊ฒƒ์ด๋ผ๊ณค ์‰ฝ๊ฒŒ ์ƒ๊ฐํ•˜์ง€ ๋ชปํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ , Stream ๋ฃจํ”„ ๋‚ด๋ถ€์—์„œ Side-Effect ๊ฐ€ ์žˆ๋Š” ๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๋ฉด ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

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

Stream ๋‚ด๋ถ€์—์„œ ์‚ฌ์ด๋“œ์ดํŽ™ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ

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

2) ํ•„์š” ์—†๋Š” ์ŠคํŠธ๋ฆผ ๋นผ๊ธฐ

์ผ๋ฐ˜์ ์ธ for ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์–ด์˜ ๋นˆ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค. ์ŠคํŠธ๋ฆผ์˜ ์‚ฌ์šฉ ์—ฌ๋ถ€์™€ ๋น„๊ตํ–ˆ์„ ๋•Œ, ์ŠคํŠธ๋ฆผ์„ ์–ต์ง€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐ€๋…์„ฑ์ด๋‚˜ ํšจ์œจ์„ฑ์ด ์˜คํžˆ๋ ค ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

์ŠคํŠธ๋ฆผ ์‚ฌ์šฉ vs ์ผ๋ฐ˜ for ๋ฃจํ”„

  1. ์ŠคํŠธ๋ฆผ์˜ ์ ์ ˆํ•œ ์‚ฌ์šฉ
    • ์ŠคํŠธ๋ฆผ์€ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜๊ณผ ํ‰๊ฐ€๋ฅผ ํ•จ์ˆ˜ํ˜• ์Šคํƒ€์ผ๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๊ทธ๋Ÿฌ๋‚˜ ์ŠคํŠธ๋ฆผ ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ž‘์—…์€ ์ŠคํŠธ๋ฆผ์˜ ์›๋ž˜ ๋ชฉ์ ์— ๋งž์ง€ ์•Š์œผ๋ฉฐ, ์ฝ”๋“œ์˜ ๋ช…ํ™•์„ฑ์„ ํ•ด์นœ๋‹ค.
    • ์‚ฌ์‹ค ๋งŽ์ด ๋Œ๋ฆฌ์ง€ ์•Š์œผ๋ฉด for๋ฌธ๊ณผ ์„ฑ๋Šฅ์  ์ฐจ์ด๊ฐ€ ๋ณ„๋กœ ์—†๋‹ค.
  2. ์ผ๋ฐ˜ for ๋ฃจํ”„์˜ ์žฅ์ 
    • ์ผ๋ฐ˜์ ์ธ ์ž๋ฐ” ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ ์นœ์ˆ™ํ•˜๋ฉฐ, ๋ช…ํ™•ํ•˜๊ณ  ์ง๊ด€์ ์ด๋‹ค.
    • ๋ฐ์ดํ„ฐ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ์™ธ๋ถ€ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์ž‘์—…์—๋Š” ์ŠคํŠธ๋ฆผ๋ณด๋‹ค for ๋ฃจํ”„๊ฐ€ ๋” ์ ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ŠคํŠธ๋ฆผ์˜ forEach๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋ณด๋‹ค ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๋†’์€ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

์ŠคํŠธ๋ฆผ์„ ์–ต์ง€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฌธ์ œ

์ŠคํŠธ๋ฆผ์˜ forEach๋Š” ๋ฐ์ดํ„ฐ์˜ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•  ๋•Œ ์ ํ•ฉํ•˜์ง€๋งŒ, ๊ณ„์‚ฐ ๊ทธ ์ž์ฒด๋ฅผ ์ŠคํŠธ๋ฆผ ๋‚ด๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์ ์ ˆํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

์ด์ „ ์ŠคํŠธ๋ฆผ ์ฝ”๋“œ (์ž˜๋ชป๋œ ์ŠคํŠธ๋ฆผ ์‚ฌ์šฉ)

์‚ฌwords.stream().forEach(
    word -> freq.merge(word.toLowerCase(), 1L, Long::sum)
);
  • ์ด ์ฝ”๋“œ๋Š” ์™ธ๋ถ€ ์ƒํƒœ(freq)๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ถ€์ž‘์šฉ(Side-Effect)์ด ๋ฐœ์ƒํ•œ๋‹ค.
  • ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ (๋ฐ์ดํ„ฐ ๋ณ€ํ™˜๊ณผ ํ‰๊ฐ€)๊ฐ€ ์•ฝํ™”๋˜์—ˆ์œผ๋ฉฐ, ๋‹จ์ˆœํžˆ forEach๋ฅผ ์–ต์ง€๋กœ ์‚ฌ์šฉํ•œ ๊ฒƒ์— ๋ถˆ๊ณผํ•˜๋‹ค.
  • ์ผ๋ฐ˜ for ๋ฃจํ”„๋ณด๋‹ค ๊ฐ€๋…์„ฑ์ด ๋‚ฎ์•„์งˆ ์ˆ˜ ์žˆ๋‹ค.

์ผ๋ฐ˜ for ๋ฃจํ”„ ์ฝ”๋“œ

์•„๋ž˜ ์ฝ”๋“œ๋Š” ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ผ๋ฐ˜์ ์ธ for ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์–ด์˜ ๋นˆ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์ฝ”๋“œ

@Test
public void wordFreq1Test() {
    List<String> words = Arrays.asList(
        "stop", "spot", "trim", "meet",
        "ball", "free", "trim", "meet"
    );

    Map<String, Long> freq = new HashMap<>();

    // ์ผ๋ฐ˜์ ์ธ for ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉ
    for (String word : words) {
        // ๋‹จ์–ด๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๋นˆ๋„์ˆ˜๋ฅผ ๊ฐฑ์‹ 
        freq.merge(word.toLowerCase(), 1L, Long::sum);
    }

    System.out.println("words = " + words); // ์ž…๋ ฅ ๋‹จ์–ด ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ
    System.out.println("freq = " + freq);  // ๋‹จ์–ด ๋นˆ๋„ ์ถœ๋ ฅ
}
  • ์™ธ๋ถ€ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์ž‘์—…์—๋Š” for ๋ฃจํ”„๊ฐ€ ๋” ์ ํ•ฉํ•˜๋‹ค.
  • ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๊ณ ๋ คํ–ˆ์„ ๋•Œ, ์ต์ˆ™ํ•œ ์ฝ”๋“œ ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ค.

์ŠคํŠธ๋ฆผ์˜ forEach ์ฝ”๋“œ๋Š” println() ๊ณผ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ๊ณ„์‚ฐ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•  ๋•Œ๋Š” ์œ ์šฉํ•˜๋‹ค.๊ทธ๋Ÿฌ๋‚˜ ๊ณ„์‚ฐ ๊ทธ ์ž์ฒด์—๋Š” ์˜คํžˆ๋ ค ๋‘๋ฒˆ์งธ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ผ๋ฐ˜์ ์ธ ์ž๋ฐ”์˜ for ๋ฌธ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๊น”๋”ํ•œ ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค.

3) ๋‹จ์–ด ๊ฐœ์ˆ˜ ์„ธ๊ธฐ 2 : ์ข…๋‹จ ์—ฐ์‚ฐ ์ด์šฉํ•˜๊ธฐ(Collectors.groupingBy๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ)

import static java.util.stream.Collectors.*;

@Test
public void wordFreqCollectorTest() {
    List<String> words = Arrays.asList(
        "stop", "spot", "trim", "meet", 
        "ball", "free", "trim", "meet"
    );

    // Collectors๋ฅผ ์‚ฌ์šฉํ•ด ๋‹จ์–ด ๋นˆ๋„ ๊ณ„์‚ฐ
   // groupingBy: ๋‹จ์–ด๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๊ทธ๋ฃนํ™”
  // counting: ๊ฐ ๊ทธ๋ฃน์˜ ์š”์†Œ ๊ฐœ์ˆ˜ ๊ณ„์‚ฐ
    Map<String, Long> freq = words.stream()
                                  .collect(groupingBy(String::toLowerCase, counting()));

    System.out.println("freq = " + freq);
}

groupingBy์™€ counting์„ ์กฐํ•ฉํ•˜์—ฌ ์ŠคํŠธ๋ฆผ ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์™€ ๊ฒฐ๊ณผ ์ƒ์„ฑ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

freq = {stop=1, spot=1, trim=2, meet=2, ball=1, free=1}
  • ์˜๋„๊ฐ€ ๋ช…ํ™•: ๋‹จ์–ด๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ๊ฐ ๊ทธ๋ฃน์˜ ๋นˆ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์ž‘์—…์ž„์„ ์ฝ”๋“œ์—์„œ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์™ธ๋ถ€ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์—์„œ๋„ ์•ˆ์ „ํ•˜๋‹ค.
  • ๋ฌธ์ž์—ด์„ toLowerCase() ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๊ทธ๋ฃนํ•‘ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋„๊ฐ€ ๋ณด์ธ๋‹ค.
  • ๊ทธ๋ฃนํ•‘๋œ key ์— ๋Œ€ํ•œ value ๋Š” ๋‹จ์–ด์˜ ๊ฐœ์ˆ˜์ธ counting() ์ด ๋“ค์–ด๊ฐˆ ๊ฒƒ์ด๋‹ค.
  • groupingBy() ๋‚˜ counting() ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€๋…์„ฑ ์ข‹๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š” Collectors ์˜ ๋ฉค๋ฒ„๋ฅผ ์ •์  ์ž„ํฌํŠธํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Stream์˜ forEach์™€ ์ˆ˜์ง‘๊ธฐ(Collector)์˜ ์ฐจ์ด์ 

  • forEach๋Š” ์ŠคํŠธ๋ฆผ์˜ ์ตœ์ข… ์—ฐ์‚ฐ ์ค‘ ํ•˜๋‚˜๋กœ, ์ŠคํŠธ๋ฆผ์˜ ๊ฐ ์š”์†Œ๋ฅผ ์†Œ๋น„ํ•˜๋ฉฐ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ธฐ๋Šฅ์ด ์ œํ•œ์ ์ด๊ณ , ์ŠคํŠธ๋ฆผ์˜ ๋ณธ๋ž˜ ์˜๋„์ธ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์™€๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ€๋ฉฐ, ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.
  • ์ŠคํŠธ๋ฆผ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ž‘์—…์—๋Š” Collectors๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ํ•ฉํ•˜๋‹ค. ํŠนํžˆ, ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜์ด๋‚˜ ๊ทธ๋ฃนํ•‘ ์ž‘์—…์—์„œ Collectors๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

forEach์˜ ํ•œ๊ณ„

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

์ˆ˜์ง‘๊ธฐ(Collector)๋ฅผ ํ™œ์šฉํ•œ ์ŠคํŠธ๋ฆผ ์ฝ”๋“œ

Java์˜ java.util.stream.Collectors ํด๋ž˜์Šค๋Š” ์ŠคํŠธ๋ฆผ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•œ ํ›„ ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜๊ฑฐ๋‚˜ ์ง‘๊ณ„ํ•˜๋ฉฐ, ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ€๋…์„ฑ ๋†’์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

forEach ์—ฐ์‚ฐ์€ ์ŠคํŠธ๋ฆผ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๊ณ , ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ๋Š” ์“ฐ์ง€ ๋ง์ž. ์ˆ˜์ง‘๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ŠคํŠธ๋ฆผ์˜ ์›์†Œ๋ฅผ ์†์‰ฝ๊ฒŒ ์ปฌ๋ ‰์…˜์œผ๋กœ ๋ชจ์„ ์ˆ˜ ์žˆ๋‹ค. ์ˆ˜์ง‘๊ธฐ๋Š” ์ด ์„ธ ๊ฐ€์ง€๋กœ, toListO, toSetO, toCollection(collectionFactory)๊ฐ€ ๊ทธ ์ฃผ์ธ๊ณต์ด๋‹ค.

4) ์ƒ์œ„ 2๊ฐœ์˜ ๋‹จ์–ด ์ถ”์ถœํ•˜๊ธฐ

@Test
public void topTwoWordsTest() {
    // ๋‹จ์–ด ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
    List<String> words = Arrays.asList("stop", "spot", "trim", "meet", "ball", "free", "trim", "trim", "meet");

    // ๋‹จ์–ด ๋นˆ๋„ ์ˆ˜ ๊ณ„์‚ฐ
    Map<String, Long> freq = words.stream()
                                  .collect(groupingBy(String::toLowerCase, counting()));

    // ๋‹จ์–ด๋ฅผ ๋นˆ๋„ ์ˆ˜ ๊ธฐ์ค€์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ ํ›„ ์ƒ์œ„ 2๊ฐœ๋งŒ ์ถ”์ถœ
    List<String> topTwo = freq.keySet() // Map์˜ keySet์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜
                              .stream()
                              .sorted(Comparator.comparing(freq::get).reversed()) // ๋นˆ๋„ ์ˆ˜ ๊ธฐ์ค€ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
                              .limit(2) // ์ƒ์œ„ 2๊ฐœ๋งŒ ์ถ”์ถœ
                              .collect(Collectors.toList()); // ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ์ˆ˜์ง‘

    // ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    System.out.println("topTwo = " + topTwo); // ์ƒ์œ„ 2๊ฐœ์˜ ๋‹จ์–ด ์ถœ๋ ฅ
}
topTwo = [trim, meet]

๋งˆ์ง€๋ง‰ toList๋Š” Collectors์˜ ๋ฉ”์„œ๋“œ๋‹ค. ์ด์ฒ˜๋Ÿผ Collectors์˜ ๋ฉค๋ฒ„๋ฅผ ์ •์  ์ž„ํฌํŠธํ•˜์—ฌ ์“ฐ๋ฉด ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์ ธ, ํ”ํžˆ๋“ค ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•œ๋‹ค.

  • ์ด ์ฝ”๋“œ์—์„œ ์–ด๋ ค์šด ๋ถ€๋ถ„์€ sorted์— ๋„˜๊ธด ๋น„๊ต์ž, ์ฆ‰ comparing(freq::get). reversed()๋ฟ์ด๋‹ค
  • comparing ๋ฉ”์„œ๋“œ๋Š” ํ‚ค ์ถ”์ถœ ํ•จ์ˆ˜๋ฅผ ๋ฐ›๋Š” ๋น„๊ต์ž ์ƒ์„ฑ ๋ฉ”์„œ๋“œ๋‹ค. ํ•œ์ •์  ๋ฉ”์„œ๋“œ ์ฐธ์กฐ์ด์ž, ์—ฌ๊ธฐ์„œ ํ‚ค ์ถ”์ถœ ํ•จ์ˆ˜๋กœ ์“ฐ์ธ freq::get์€ ์ž…๋ ฅ๋ฐ›์€ ๋‹จ์–ด(ํ‚ค)๋ฅผ ๋นˆ๋„ํ‘œ์—์„œ ์ฐพ์•„(์ถ”์ถœ) ๊ทธ ๋นˆ๋„๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

3. Collectors API์™€ ํ™œ์šฉ ์ •๋ฆฌ

1) Collectors์˜ ์ฃผ์š” ๋ฉ”์„œ๋“œ

Collectors๋Š” ์ŠคํŠธ๋ฆผ ๋ฐ์ดํ„ฐ๋ฅผ ํŠน์ • ์ปฌ๋ ‰์…˜, ๋งต, ๋ฌธ์ž์—ด ๋“ฑ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜, ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜๊ฑฐ๋‚˜, ์ง‘๊ณ„ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

์ˆ˜์ง‘๊ธฐ ๋ฉ”์„œ๋“œ

๋ฉ”์„œ๋“œ ์„ค๋ช… ์˜ˆ์‹œ
toList() ์ŠคํŠธ๋ฆผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ์ˆ˜์ง‘. List<String> result = stream.collect(toList());
toSet() ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘ํ•ฉ(Set)์œผ๋กœ ์ˆ˜์ง‘. Set<String> result = stream.collect(toSet());
toMap() ํ‚ค์™€ ๊ฐ’์„ ๋งคํ•‘ํ•˜์—ฌ ๋งต ์ƒ์„ฑ. ํ‚ค ์ถฉ๋Œ ์‹œ ๋ณ‘ํ•ฉ ๋กœ์ง์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Œ. toMap(keyMapper, valueMapper, mergeFunction)
groupingBy() ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ๋งต ์ƒ์„ฑ. groupingBy(String::toLowerCase, counting())
partitioningBy() ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ true/false ๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆ”. partitioningBy(word -> word.equals("stop"))
joining() ๋ฌธ์ž์—ด ์ŠคํŠธ๋ฆผ์„ ์—ฐ๊ฒฐ. ๊ตฌ๋ถ„์ž, ์ ‘๋‘์‚ฌ, ์ ‘๋ฏธ์‚ฌ ์ง€์ • ๊ฐ€๋Šฅ. joining(", ", "๋ง›์žˆ๋Š” ", "์ด ์ข‹์•„")

์ง‘๊ณ„ ๋ฉ”์„œ๋“œ

๋ฉ”์„œ๋“œ ์„ค๋ช… ์˜ˆ์‹œ
counting() ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋ฅผ ์…ˆ. collect(counting())
summingInt() ์š”์†Œ์˜ ํ•ฉ๊ณ„๋ฅผ ๊ตฌํ•จ. collect(summingInt(Student::getScore))
averagingInt() ์š”์†Œ์˜ ํ‰๊ท ์„ ๊ตฌํ•จ. collect(averagingInt(Student::getScore))
summarizingInt() ํ•ฉ๊ณ„, ํ‰๊ท , ์ตœ์†Œ, ์ตœ๋Œ€, ๊ฐœ์ˆ˜๋ฅผ ํ•œ ๋ฒˆ์— ํ†ต๊ณ„๋กœ ๊ตฌํ•จ. collect(summarizingInt(Student::getScore))

2) Operation ์—ด๊ฑฐ ํƒ€์ž…์„ ์ด์šฉํ•œ ์—ฐ์‚ฐ์ž ๋งคํ•‘

symbol๋ณ„ ์—ฐ์‚ฐ์ž ๊ธฐํ˜ธ ๋งคํ•‘ํ•˜๊ธฐ: ์ธ์ž 2๊ฐœ์งœ๋ฆฌ toMap()

enum Operation {
    PLUS("+", "plus", (x, y) -> x + y),
    MINUS("-", "minus", (x, y) -> x - y),
    TIMES("*", "times", (x, y) -> x * y),
    DIVIDE("/", "divide", (x, y) -> x / y);

    private final String symbol; // ์—ฐ์‚ฐ์ž ๊ธฐํ˜ธ
    private final String english; // ์—ฐ์‚ฐ์ž์˜ ์˜์–ด ํ‘œํ˜„
    private final BinaryOperator<Double> op; // ์—ฐ์‚ฐ์ž ๋กœ์ง

    // ์ƒ์„ฑ์ž
    Operation(String symbol, String english, BinaryOperator<Double> op) {
        this.symbol = symbol;
        this.english = english;
        this.op = op;
    }

    @Override
    public String toString() {
        return symbol; // ์—ฐ์‚ฐ์ž ๊ธฐํ˜ธ๋ฅผ ๋ฐ˜ํ™˜
    }

    public String toEnglish() { return english; } // ์—ฐ์‚ฐ์ž์˜ ์˜์–ด ํ‘œํ˜„ ๋ฐ˜ํ™˜

    public double apply(double x, double y) {
        return op.apply(x, y); // ์—ฐ์‚ฐ์ž ๋กœ์ง ์‹คํ–‰
    }
}

@Test
public void stringToEnumTest() {
    // Operation ์—ด๊ฑฐํ˜•์„ ์˜์–ด ํ‘œํ˜„์„ ํ‚ค, Operation ์ž์ฒด๋ฅผ ๊ฐ’์œผ๋กœ ๋งคํ•‘
    Map<String, Operation> operationMap = Stream.of(Operation.values())
                                                .collect(toMap(e -> e.english, e -> e));

    System.out.println("operationMap = " + operationMap);
    // ๊ฒฐ๊ณผ: {minus=-, times=*, divide=/, plus=+}
}
  • toMap์„ ์‚ฌ์šฉํ•˜์—ฌ english๋ฅผ ํ‚ค๋กœ, ์—ด๊ฑฐํ˜• ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ’์œผ๋กœ ๋งคํ•‘.
  • toMap(keyMapper, valueMapper) ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ๋˜๋ฉฐ, ํ‚ค์™€ ๊ฐ’์„ ๊ฐ๊ฐ ์–ด๋–ป๊ฒŒ ๋งคํ•‘ํ• ์ง€ ์ •์˜.
  • ๊ฒฐ๊ณผ: {minus=-, times=*, divide=/, plus=+}

3) ์•„ํ‹ฐ์ŠคํŠธ์˜ ๋ฒ ์ŠคํŠธ ์•จ๋ฒ” ์ฐพ๊ธฐ

List ๋ฐ์ดํ„ฐ Map<String, Album>์œผ๋กœ merge()ํ•˜๊ธฐ: ์ธ์ž 3๊ฐœ์งœ๋ฆฌ toMap()

class Album {
    private final String artist;
    private final String name;
    private final int sales;

    public Album(String artist, String name, int sales) {
        this.artist = artist;
        this.name = name;
        this.sales = sales;
    }

    public String artist() { return artist; }
    public int sales() { return sales; }

    @Override
    public String toString() {
        return "Album{name='" + name + "', sales=" + sales + "}";
    }
}

@Test
public void bestAlbumPerArtist() {
    // ์•จ๋ฒ” ๋ฐ์ดํ„ฐ ์ƒ์„ฑ
    List<Album> albums = Arrays.asList(
        new Album("Jake", "์ œ์ดํฌ 1์ง‘", 100),
        new Album("Jake", "์ œ์ดํฌ 2์ง‘", 250),
        new Album("Jack", "์žญ 1์ง‘", 990),
        new Album("Jack", "์žญ 2์ง‘", 140)
    );

    // ์•„ํ‹ฐ์ŠคํŠธ๋ณ„ ๋ฒ ์ŠคํŠธ ์•จ๋ฒ” ์ฐพ๊ธฐ
    Map<String, Album> topHits = albums.stream()
                                       .collect(toMap(
                                           Album::artist, // Key: ์•„ํ‹ฐ์ŠคํŠธ ์ด๋ฆ„
                                           album -> album, // Value: ์•จ๋ฒ” ๊ฐ์ฒด
                                           BinaryOperator.maxBy(Comparator.comparing(Album::sales)) // ๋ณ‘ํ•ฉ: ์ตœ๊ณ  ํŒ๋งค๋Ÿ‰ ๊ธฐ์ค€
                                       ));

    System.out.println("topHits = " + topHits);
    // ์ถœ๋ ฅ: {Jake=Album{name='์ œ์ดํฌ 2์ง‘', sales=250}, Jack=Album{name='์žญ 1์ง‘', sales=990}}
}
  • toMap(keyMapper, valueMapper, mergeFunction) ํ˜•ํƒœ๋ฅผ ์‚ฌ์šฉ.
  • ๋ณ‘ํ•ฉ ํ•จ์ˆ˜(mergeFunction)๋กœ BinaryOperator.maxBy๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ ์•„ํ‹ฐ์ŠคํŠธ์˜ ํŒ๋งค๋Ÿ‰์ด ๊ฐ€์žฅ ๋งŽ์€ ์•จ๋ฒ”์„ ์„ ํƒ.
  • ๊ฒฐ๊ณผ: {Jake=Album{name='์ œ์ดํฌ 2์ง‘', sales=250}, Jack=Album{name='์žญ 1์ง‘', sales=990}}

4) ๊ธฐํƒ€ ํ™œ์šฉ ์‚ฌ๋ก€

๋‹จ์–ด ๋ฆฌ์ŠคํŠธ๋ฅผ ์•ŒํŒŒ๋ฒณ ์ˆœ์„œ๋กœ ๊ทธ๋ฃนํ™”

@Test
public void wordFreqGroupingTest() {
    List<String> words = Arrays.asList("stop", "spot", "trim", "meet", "ball", "free", "triM", "TriM", "meet");

    // ๋‹จ์–ด๋ฅผ ์•ŒํŒŒ๋ฒณ ์ˆœ์œผ๋กœ ์ •๋ ฌํ•œ ๊ฒฐ๊ณผ๋ฅผ Key๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ๋ฃนํ™”
    Map<String, List<String>> alphabetizedMap = words.stream()
                                                     .collect(groupingBy(this::alphabetize));

    System.out.println("alphabetizedMap = " + alphabetizedMap);
    // ์ถœ๋ ฅ: {eefr=[free], opst=[stop, spot], imrt=[trim], ...}
}

private String alphabetize(String s) {
    char[] a = s.toCharArray();
    Arrays.sort(a); // ๋‹จ์–ด์˜ ๋ฌธ์ž๋ฅผ ์ •๋ ฌ
    return new String(a); // ์ •๋ ฌ๋œ ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜
}
  • groupingBy๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ŒํŒŒ๋ฒณ ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ ๋‹จ์–ด๋ฅผ ํ‚ค๋กœ ๊ทธ๋ฃนํ™”.
  • ๊ฒฐ๊ณผ: {eefr=[free], opst=[stop, spot], imrt=[trim], eemt=[meet, meet], ...}

ํ•™์ƒ ์ ์ˆ˜ ํ†ต๊ณ„

@Test
public void studentScoreStatistics() {
    List<Student> students = Arrays.asList(
        new Student("Jake", 15),
        new Student("Jackson", 55),
        new Student("Joe", 85),
        new Student("Amy", 21),
        new Student("Roy", 33)
    );

    // ํ•™์ƒ ์ ์ˆ˜ ํ†ต๊ณ„
    IntSummaryStatistics stats = students.stream()
                                         .collect(summarizingInt(Student::getScore));

    System.out.println(stats);
    // ์ถœ๋ ฅ: IntSummaryStatistics{count=5, sum=209, min=15, average=41.800000, max=85}
}
  • summarizingInt๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•™์ƒ ์ ์ˆ˜์˜ ํ†ต๊ณ„ ์ •๋ณด๋ฅผ ํ•œ ๋ฒˆ์— ์ˆ˜์ง‘.
  • ๊ฒฐ๊ณผ: count, sum, min, average, max๊ฐ€ ํฌํ•จ๋œ IntSummaryStatistics ๋ฐ˜ํ™˜.

๋ฌธ์ž์—ด ์—ฐ๊ฒฐ

@Test
public void joiningTest() {
    List<String> food = Arrays.asList("ํ”ผ์ž", "ํ–„๋ฒ„๊ฑฐ", "์น˜ํ‚จ");

    // ๋ฌธ์ž์—ด ์—ฐ๊ฒฐ: ๊ตฌ๋ถ„์ž, ์ ‘๋‘์‚ฌ, ์ ‘๋ฏธ์‚ฌ ์ง€์ •
    String result = food.stream()
                        .collect(joining(", ", "๋ง›์žˆ๋Š” ", "์ด ์ข‹์•„"));

    System.out.println(result); // ์ถœ๋ ฅ: ๋ง›์žˆ๋Š” ํ”ผ์ž, ํ–„๋ฒ„๊ฑฐ, ์น˜ํ‚จ์ด ์ข‹์•„
}
  • joining(delimiter, prefix, suffix)๋กœ ๋ฌธ์ž์—ด ์—ฐ๊ฒฐ.
  • ๊ฒฐ๊ณผ: "๋ง›์žˆ๋Š” ํ”ผ์ž, ํ–„๋ฒ„๊ฑฐ, ์น˜ํ‚จ์ด ์ข‹์•„"

5) Collectors์˜ ํŠน์ง•๊ณผ ํ™œ์šฉ ๊ฐ€์ด๋“œ

Collectors์˜ ์žฅ์ 

  1. ๊ฐ€๋…์„ฑ:
    • groupingBy, toMap ๋“ฑ์€ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์˜๋„๋ฅผ ์ฝ”๋“œ์—์„œ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚ธ๋‹ค.
  2. ํšจ์œจ์„ฑ:
    • ์ŠคํŠธ๋ฆผ์„ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ ์ˆœํšŒํ•˜๋ฉด์„œ ํ•„์š”ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  3. ์œ ์—ฐ์„ฑ:
    • ๋‹ค์–‘ํ•œ ์ˆ˜์ง‘๊ธฐ ์กฐํ•ฉ์„ ํ†ตํ•ด ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

Collectors ์‚ฌ์šฉ ๊ฐ€์ด๋“œ

  1. toMap ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์ :
    • ํ‚ค๊ฐ€ ์ค‘๋ณต๋  ๊ฒฝ์šฐ IllegalStateException์ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ, ๋ณ‘ํ•ฉ ํ•จ์ˆ˜(mergeFunction)๋ฅผ ์ œ๊ณตํ•ด์•ผํ•œ๋‹ค.
  2. groupingBy์™€ partitioningBy ์ฐจ์ด:
    • groupingBy๋Š” ์—ฌ๋Ÿฌ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ๊ทธ๋ฃนํ™”.
    • partitioningBy๋Š” true/false ๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋ถ„๋ฅ˜.
  3. joining ํ™œ์šฉ:
    • ๊ตฌ๋ถ„์ž, ์ ‘๋‘์‚ฌ, ์ ‘๋ฏธ์‚ฌ๋ฅผ ์ง€์ •ํ•˜์—ฌ ๋ฌธ์ž์—ด์„ ์‰ฝ๊ฒŒ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅ.
  4. ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ:
    • groupingByConcurrent, toConcurrentMap์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ ๊ฒฐ๊ณผ๋ฅผ ConcurrentHashMap์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

6) ์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”์™€ Collectors

forEach์˜ ํ•œ๊ณ„

  • forEach๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•˜๊ฑฐ๋‚˜, ๋ณด๊ณ  ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜์ด๋‚˜ ์ง‘๊ณ„ ์ž‘์—…์€ Collectors๋ฅผ ํ™œ์šฉํ•ด์•ผ ๊ฐ€๋…์„ฑ๊ณผ ํšจ์œจ์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

์ŠคํŠธ๋ฆผ ํ™œ์šฉ ์›์น™

  1. ์˜๋„๋ฅผ ๋ช…ํ™•ํžˆ ํ‘œํ˜„:
    • ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ์ง‘๊ณ„ํ•  ๋•Œ ์ŠคํŠธ๋ฆผ์˜ ๊ฐ ๋‹จ๊ณ„๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์„ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์•ผ ํ•œ๋‹ค.
  2. ํ•จ์ˆ˜ํ˜• ์Šคํƒ€์ผ ์œ ์ง€:
    • ์™ธ๋ถ€ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ํ”ผํ•˜๊ณ , ์ŠคํŠธ๋ฆผ ๋‚ด๋ถ€์—์„œ ์ž‘์—…์„ ์™„๋ฃŒํ•˜๋„๋ก ์„ค๊ณ„ํ•œ๋‹ค.

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

ํ•ต์‹ฌ ์ •๋ฆฌ

  • ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์€ ๋ถ€์ž‘์šฉ ์—†๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด์— ์žˆ๋‹ค.
  • ์ŠคํŠธ๋ฆผ๋ฟ ์•„๋‹ˆ๋ผ ์ŠคํŠธ๋ฆผ ๊ด€๋ จ ๊ฐ์ฒด์— ๊ฑด๋„ค์ง€๋Š” ๋ชจ๋“  ํ•จ์ˆ˜ ๊ฐ์ฒด๊ฐ€ ๋ถ€์ž‘์šฉ์ด ์—†์–ด์•ผ ํ•œ๋‹ค.
  • ์ข…๋‹จ ์—ฐ์‚ฐ ์ค‘ forEach๋Š” ์ŠคํŠธ๋ฆผ์ด ์ˆ˜ํ–‰ํ•œ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•  ๋•Œ๋งŒ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค. ๊ณ„์‚ฐ ์ž์ฒด์—๋Š” ์ด์šฉํ•˜์ง€ ๋ง์ž.
  • ์ŠคํŠธ๋ฆผ์„ ์˜ฌ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ˆ˜์ง‘๊ธฐ๋ฅผ ์ž˜ ์•Œ์•„๋‘ฌ์•ผ ํ•œ๋‹ค. ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ˆ˜์ง‘๊ธฐ ํŒฉํ„ฐ๋ฆฌ๋Š” toList, toSet, toHap, groupingBy, joining์ด๋‹ค

์ถœ์ฒ˜ ๋ฐ ์ฐธ๊ณ