๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“š Kotlin

[Effective Kotlin] ์•„์ดํ…œ 49. ํ•˜๋‚˜ ์ด์ƒ์˜ ์ฒ˜๋ฆฌ ๋‹จ๊ณ„๋ฅผ ๊ฐ€์ง„ ๊ฒฝ์šฐ์—๋Š” ์‹œํ€€์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

by GroovyArea 2023. 2. 4.

์ฝ”ํ‹€๋ฆฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Collection ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ํ•จ์ˆ˜๋ฅผ ์ง€์›ํ•œ๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ iterable ์—์„œ๋„ filter, map ๋“ฑ ๋™์ผํ•œ ํ•จ์ˆ˜๋ฅผ ์ง€์›ํ•˜๋ฉด์„œ, ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ์ง€์—ฐ ์—ฐ์‚ฐ์„ ์œ„ํ•ด์„œ๋Š” ์ž๋ฐ”์™€ ๊ฐ™์€ Stream, ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” Sequence๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ํ•œ๋‹ค.

์ •๋ฆฌํ•ด๋ณด์ž.

 

Iterable๊ณผ Sequence

public inline fun<T> Iterable<T>.filter(
	predicate: (T) -> Boolean
): List<T> {
	return filterTo(ArrayList<T>(), predicate)
}

public fun <T> Sequence<T>.filter(
	predicate: (T) -> Boolean
): Sequence<T> {
	return FilteringSequence(this, true, predicate)
}

iterable์˜ filter์™€ sequence์˜ filter๋Š” ๋‘˜ ๋‹ค ๋™์ผํ•œ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์ด์ง€๋งŒ, ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅด๋‹ค.

 

๋˜, ์ผ๋ฐ˜์ ์ธ ์ปฌ๋ ‰์…˜ ์ฒ˜๋ฆฌ ์—ฐ์‚ฐ์€ ํ˜ธ์ถœํ•  ๋Œ€ ์—ฐ์‚ฐ์ด ์ด๋ฃจ์–ด์ง„๋‹ค.

๋ฐ˜๋ฉด, ์‹œํ€€์Šค๋Š” ์ตœ์ข… ์—ฐ์‚ฐ(toList ๋“ฑ๋“ฑ)์ด ์ผ์–ด๋‚  ๋•Œ๊นŒ์ง€ ์–ด๋– ํ•œ ์—ฐ์‚ฐ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค.

 

์‹œํ€€์Šค ์ง€์—ฐ ์ฒ˜๋ฆฌ์˜ ์žฅ์ 

  • ์ž์—ฐ์Šค๋Ÿฌ์šด ์ฒ˜๋ฆฌ ์ˆœ์„œ๋ฅผ ์œ ์ง€
  • ์ตœ์†Œํ•œ๋งŒ ์—ฐ์‚ฐ
  • ๋ฌดํ•œ ์‹œํ€€์Šค ํ˜•ํƒœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ๊ฐ๊ฐ์˜ ๋‹จ๊ณ„์—์„œ ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ค์ง€ ์•Š์Œ
        sequenceOf(1, 2, 3)
            .filter { print("F$it, "); it % 2 == 1 }
            .map { print("M$it, "); it * 2 }
            .forEach { print("E$it, ") }
    // F1, M1, E2, F2, F3, M3, E6,
    
    listOf(1, 2, 3)
            .filter { print("F$it, "); it % 2 == 1 }
            .map { print("M$it, "); it * 2 }
            .forEach { print("E$it, ") }
    // F1, F2, F3, M1, M3, E2, E6,

์‹œํ€€์Šค์˜ ์ฒ˜๋ฆฌ๋Š” ์š”์†Œ ํ•˜๋‚˜ํ•˜๋‚˜๋‹น ์ง€์ •ํ•œ ์—ฐ์‚ฐ์„ ํ•œ๊บผ๋ฒˆ์— ์ฒ˜๋ฆฌํ•œ๋‹ค. => element-by-element order

์ดํ„ฐ๋Ÿฌ๋ธ”์€ ์š”์†Œ ์ „์ฒด๋ฅผ ๋Œ€์ƒ์„ ๋Œ€์ƒ์œผ๋กœ ์—ฐ์‚ฐ์„ ์ฐจ๊ทผ์ฐจ๊ทผ ์ ์šฉํ•œ๋‹ค. => step-by-step order

 

์‹œ์ปจ์Šค์˜ ์ฒ˜๋ฆฌ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๊ณ ์ „ ๋ฐ˜๋ณต๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ํ›จ์”ฌ ๋น ๋ฅด๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ์ฒ˜๋ฆฌ์ด๋‹ค.

๋กœ์šฐ ๋ ˆ๋ฒจ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์ตœ์ ํ™”๊ฐ€ ์ง„ํ–‰๋˜๋ฉด, ์ฒ˜๋ฆฌ๊ฐ€ ํ›จ์”ฌ ๋นจ๋ผ์งˆ ๊ฒƒ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

์ตœ์†Œ ์—ฐ์‚ฐ

๋ชจ๋“  ๊ฒƒ์„ ์š”์†Œ ์ „์ฒด์— ์ ์šฉํ•˜๋Š” ์ดํ„ฐ๋Ÿฌ๋ธ”๊ณผ ๋‹ฌ๋ฆฌ, ์ค‘๊ฐ„ ์—ฐ์‚ฐ์ด ์žˆ๋Š” ์‹œํ€€์Šค๋Š” ์›ํ•˜๋Š” ์š”์†Œ์—๋งŒ ์—ฐ์‚ฐ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

(1..10).asSequence()
            .filter { print("F$it, "); it % 2 == 1 }
            .map { print("M$it, "); it * 2 }
            .find { it > 5 }
            
            // F1, M1, F2, F3, M3,
            
(1..10)
            .filter { print("F$it, "); it % 2 == 1 }
            .map { print("M$it, "); it * 2 }
            .find { it > 5 }
            
            // F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, M1, M3, M5, M7, M9

์ค‘๊ฐ„ ์ฒ˜๋ฆฌ ๋‹จ๊ณ„๋ฅผ ๋ชจ๋“  ์š”์†Œ์— ์ ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋„ ์‹œํ€€์Šค๊ฐ€ ์ด๋“์ด๋‹ค.

์š”์†Œ๋ฅผ ์„ ํƒํ•  ์—ฐ์‚ฐ์€ first์™€ take๋ฅผ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ํ•œ๋‹ค.

 

 

๊ฐ ๋‹จ๊ณ„์—์„œ ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.

ํ‘œ์ค€ ์ปฌ๋ ‰์…˜ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋Š” ๊ฐ ๋‹จ๊ณ„ ๋ณ„๋กœ ์ƒˆ๋กœ์šด ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ List๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ด๋Š” ์ปฌ๋ ‰์…˜ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋ฏ€๋กœ, ๋น„์šฉ์ด ๋ฐœ์ƒํ•˜๊ณ  ๊ทธ๋งŒํผ ๋ฌด๊ฒ๊ณ  ๋Š๋ฆฌ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

 

๋ฌด๊ฑฐ์šด ์ปฌ๋ ‰์…˜์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ํŠนํžˆ ์œ„ํ—˜ํ•˜๋‹ค.

์ž˜๋ชปํ•˜๋ฉด OOM์ด ํ„ฐ์งˆ ์ˆ˜๋„ ์žˆ๋‹ค.

 

๋ฐ˜๋ฉด, ์‹œํ€€์Šค๋Š” ์‹œํ€€์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์—,

์ด๋Ÿฌํ•œ ๊ฑฑ์ •์„ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

 

 

์ •๋ฆฌ

์ปฌ๋ ‰์…˜๊ณผ ์‹œํ€€์Šค๋Š” ๊ฐ™์€ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์ง€์›ํ•˜๊ณ , ์‚ฌ์šฉ ํ˜•ํƒœ๊ฐ€ ๋น„์Šทํ•˜์ง€๋งŒ, Lazy ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ๋œ๋‹ค๋Š” ์‹œํ€€์Šค์˜ ์žฅ์ ์€ ๋„˜์‚ฌ๋ฒฝ์ด๋‹ค.

์•ž์œผ๋กœ ์ž๋ฐ”์˜ Stream ์ฒ˜๋Ÿผ ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” Sequence๋ฅผ ์ž์ฃผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

๋ฐ˜์‘ํ˜•