๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Programming/Java

28 Stream

by Dowon Kang 2024. 1. 21.

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

์ŠคํŠธ๋ฆผ? ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ ์†Œ์Šค(์ปฌ๋ ‰์…˜, ๋ฐฐ์—ด)๋ฅผ ํ‘œ์ค€ํ™”๋œ ๋ฐฉ๋ฒ•์œผ๋กœ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ๊ฒƒ

 

์ŠคํŠธ๋ฆผ(Stream)์€ ์ค‘๊ฐ„ ์—ฐ์‚ฐ(Intermediate Operations)๊ณผ ์ตœ์ข… ์—ฐ์‚ฐ(Terminal Operations)์œผ๋กœ ๋‚˜๋ˆ„์–ด์ง€๋Š”๋ฐ, ์ค‘๊ฐ„ ์—ฐ์‚ฐ์€ ์ŠคํŠธ๋ฆผ์„ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ํ•„ํ„ฐ๋งํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ตœ์ข… ์—ฐ์‚ฐ์€ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์ŠคํŠธ๋ฆผ์„ ๋‹ซ๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

 

์ŠคํŠธ๋ฆผ ์ฃผ์š” ํŠน์ง• 

  1. ๋‚ด๋ถ€ ๋ฐ˜๋ณต (Internal Iteration): ์ŠคํŠธ๋ฆผ์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฉ์‹์ธ ๋‚ด๋ถ€ ๋ฐ˜๋ณต์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ๋ฐ˜๋ณต๋ฌธ์„ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ณ  ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ง€์—ฐ ํ‰๊ฐ€ (Lazy Evaluation): ์ŠคํŠธ๋ฆผ์€ ์ง€์—ฐ ํ‰๊ฐ€๋ฅผ ํ†ตํ•ด ํ•„์š”ํ•œ ์‹œ์ ๊นŒ์ง€ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ค‘๊ฐ„ ์—ฐ์‚ฐ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•˜๋”๋ผ๋„ ์‹ค์ œ๋กœ ์ฒ˜๋ฆฌ๋Š” ์ตœ์ข… ์—ฐ์‚ฐ์ด ํ˜ธ์ถœ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  3. ํŒŒ์ดํ”„๋ผ์ด๋‹ (Pipelining): ์ŠคํŠธ๋ฆผ์€ ์—ฌ๋Ÿฌ ์ค‘๊ฐ„ ์—ฐ์‚ฐ๊ณผ ์ตœ์ข… ์—ฐ์‚ฐ์„ ์ฒด์ด๋‹(Chaining)ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๊ณ  ๊ฐ€๋…์„ฑ ์žˆ๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 


 

 

์ค‘๊ฐ„ ์—ฐ์‚ฐ (Intermediate Operations)

์ค‘๊ฐ„ ์—ฐ์‚ฐ์€ ์ŠคํŠธ๋ฆผ์„ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ํ•„ํ„ฐ๋งํ•˜๋Š” ์—ฐ์‚ฐ์œผ๋กœ, ์—ฌ๋Ÿฌ ๋ฒˆ ์—ฐ์†ํ•ด์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ˜ธ์ถœ ์ˆœ์„œ์— ๋”ฐ๋ผ ์—ฐ์‚ฐ์ด ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ค‘๊ฐ„ ์—ฐ์‚ฐ์€ ์ƒˆ๋กœ์šด ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์ฒด์ด๋‹(Chaining)์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์—ฐ์‚ฐ์„ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜ ์ฝ”๋“œ์—์„œ๋Š” ์ •์ˆ˜ ๋ฆฌ์ŠคํŠธ์—์„œ ์ง์ˆ˜๋งŒ ํ•„ํ„ฐ๋งํ•˜๊ณ  ๊ฐ ์š”์†Œ๋ฅผ ์ œ๊ณฑํ•˜๋Š” ์ค‘๊ฐ„ ์—ฐ์‚ฐ์ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

๋”๋ณด๊ธฐ

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

List<Integer> evenSquared = numbers.stream()
        .filter(n -> n % 2 == 0)       // ์ค‘๊ฐ„ ์—ฐ์‚ฐ: ์ง์ˆ˜๋งŒ ํ•„ํ„ฐ๋ง
        .map(n -> n * n)              // ์ค‘๊ฐ„ ์—ฐ์‚ฐ: ๊ฐ ์š”์†Œ ์ œ๊ณฑ
        .collect(Collectors.toList());  // ์ตœ์ข… ์—ฐ์‚ฐ: ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ์ˆ˜์ง‘

System.out.println(evenSquared);  // [4, 16, 36, 64, 100]

 

1) ๋ฐ์ดํ„ฐ ์†Œ์Šค ๋ณ€๊ฒฝ ์—†์Œ: ์ŠคํŠธ๋ฆผ์€ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•˜๊ณ  ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์ค‘๊ฐ„ ์—ฐ์‚ฐ๊ณผ ์ตœ์ข… ์—ฐ์‚ฐ์„ ํ†ตํ•ด ํ•„ํ„ฐ๋ง, ๋ณ€ํ™˜ ๋˜๋Š” ์ง‘๊ณ„ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

2) ๋‚ด๋ถ€ ๋ฐ˜๋ณต (Internal Iteration): ์ŠคํŠธ๋ฆผ์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ์š”์†Œ๋ฅผ ๋ฐ˜๋ณต ์ฒ˜๋ฆฌํ•˜๋Š” ๋‚ด๋ถ€ ๋ฐ˜๋ณต์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ๋ฐ˜๋ณต์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ๋ฐ˜๋ณต๋ฌธ์„ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ์ŠคํŠธ๋ฆผ API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์š”์†Œ์— ์ ‘๊ทผํ•˜๊ณ  ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

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


3) ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ (Parallel Processing): ์ŠคํŠธ๋ฆผ์€ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ง€์›ํ•˜์—ฌ ์ž‘์—…์„ ๋™์‹œ์— ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ์ฒญํฌ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

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


4) ์ตœ์ข… ์—ฐ์‚ฐ (Terminal Operations): ์ŠคํŠธ๋ฆผ์˜ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜, ์ŠคํŠธ๋ฆผ์„ ๋‹ซ๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ข… ์—ฐ์‚ฐ์€ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•˜๋ฉฐ, ํ˜ธ์ถœ๋˜๋ฉด ์ŠคํŠธ๋ฆผ์€ ๋‹ซํžˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

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

 

 


Java streams represent a pipeline through which data will flow and the functions to operate on the data.

 

Java streams enable functional-style operations on streams of elements. A stream is an abstraction of a non-mutable collection of functions applied in some order to the data. A stream is not a collection where you can store elements.

 

'Programming > Java' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

27 Functional Interface (feat. Lambda)  (1) 2024.01.21
26 Thread  (1) 2024.01.21
25 Generics  (1) 2024.01.21
24 Enum  (0) 2024.01.21
23 Annotation  (1) 2024.01.21

๋Œ“๊ธ€