🎭 고차 함수
📖 고차 함수란?
**고차 함수(Higher-Order Function)**는 함수를 인자로 받거나 함수를 반환하는 함수입니다. Kotlin의 함수형 프로그래밍 핵심입니다!
💡 기본 개념
함수를 인자로
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
fun main() {
// 람다 전달
val sum = calculate(5, 3) { x, y -> x + y }
println(sum) // 8
val product = calculate(5, 3) { x, y -> x * y }
println(product) // 15
}
함수를 반환
fun makeMultiplier(factor: Int): (Int) -> Int {
return { number -> number * factor }
}
fun main() {
val double = makeMultiplier(2)
val triple = makeMultiplier(3)
println(double(5)) // 10
println(triple(5)) // 15
}
🔧 내장 고차 함수
filter
조건에 맞는 요소만 필터링
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6)
// 짝수만
val evens = numbers.filter { it % 2 == 0 }
println(evens) // [2, 4, 6]
// 3보다 큰 수
val greaterThan3 = numbers.filter { it > 3 }
println(greaterThan3) // [4, 5, 6]
}
map
각 요소를 변환
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// 제곱
val squared = numbers.map { it * it }
println(squared) // [1, 4, 9, 16, 25]
// 문자열로
val strings = numbers.map { "숫자: $it" }
println(strings) // [숫자: 1, 숫자: 2, ...]
}
forEach
각 요소에 작업 수행
fun main() {
val fruits = listOf("사과", "바나나", "포도")
fruits.forEach { fruit ->
println("과일: $fruit")
}
// 과일: 사과
// 과일: 바나나
// 과일: 포도
}
reduce
요소들을 누적 계산
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// 합계
val sum = numbers.reduce { acc, num -> acc + num }
println(sum) // 15
// 최댓값
val max = numbers.reduce { acc, num ->
if (num > acc) num else acc
}
println(max) // 5
}
fold
초기값과 함께 누적
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// 초기값 0에서 시작
val sum = numbers.fold(0) { acc, num -> acc + num }
println(sum) // 15
// 초기값 10에서 시작
val sumWith10 = numbers.fold(10) { acc, num -> acc + num }
println(sumWith10) // 25
}
🎯 실전 예제
커스텀 필터 함수
fun <T> customFilter(list: List<T>, predicate: (T) -> Boolean): List<T> {
val result = mutableListOf<T>()
for (item in list) {
if (predicate(item)) {
result.add(item)
}
}
return result
}
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6)
val evens = customFilter(numbers) { it % 2 == 0 }
println(evens) // [2, 4, 6]
val greaterThan3 = customFilter(numbers) { it > 3 }
println(greaterThan3) // [4, 5, 6]
}
조건 체이닝
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val result = numbers
.filter { it % 2 == 0 } // 짝수만
.map { it * it } // 제곱
.filter { it > 10 } // 10보다 큰 것만
.sorted() // 정렬
println(result) // [16, 36, 64, 100]
}
유효성 검사
fun validateInput(
input: String,
validators: List<(String) -> Boolean>
): Boolean {
return validators.all { validator -> validator(input) }
}
fun main() {
val password = "Password123"
val isValid = validateInput(password, listOf(
{ it.length >= 8 }, // 8자 이상
{ it.any { c -> c.isDigit() } }, // 숫자 포함
{ it.any { c -> c.isUpperCase() } } // 대문자 포함
))
println(if (isValid) "유효한 비밀번호" else "유효하지 않음")
}
데이터 변환 파이프라인
data class Person(val name: String, val age: Int)
fun main() {
val people = listOf(
Person("Alice", 25),
Person("Bob", 30),
Person("Charlie", 20),
Person("David", 35)
)
// 30세 이상의 이름만 대문자로
val result = people
.filter { it.age >= 30 }
.map { it.name.uppercase() }
.sorted()
println(result) // [BOB, DAVID]
}
🔍 고급 활용
함수 조합
fun <T, R, V> compose(
f: (R) -> V,
g: (T) -> R
): (T) -> V {
return { x -> f(g(x)) }
}
fun main() {
val addOne = { x: Int -> x + 1 }
val double = { x: Int -> x * 2 }
// 먼저 1을 더하고, 그 다음 2를 곱함
val addThenDouble = compose(double, addOne)
println(addThenDouble(5)) // (5 + 1) * 2 = 12
}
부분 적용
fun partial(a: Int, operation: (Int, Int) -> Int): (Int) -> Int {
return { b -> operation(a, b) }
}
fun main() {
val add5 = partial(5) { a, b -> a + b }
val multiply3 = partial(3) { a, b -> a * b }
println(add5(10)) // 15
println(multiply3(4)) // 12
}
repeat 함수
fun repeat(times: Int, action: (Int) -> Unit) {
for (i in 0 until times) {
action(i)
}
}
fun main() {
repeat(5) { index ->
println("반복 $index")
}
// 반복 0
// 반복 1
// 반복 2
// 반복 3
// 반복 4
}
📊 성능 최적화
sequence로 지연 평가
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 일반 리스트 (즉시 평가)
val result1 = numbers
.filter { println("filter: $it"); it % 2 == 0 }
.map { println("map: $it"); it * it }
.take(2)
println()
// Sequence (지연 평가)
val result2 = numbers.asSequence()
.filter { println("filter: $it"); it % 2 == 0 }
.map { println("map: $it"); it * it }
.take(2)
.toList()
}
🤔 자주 묻는 질문
Q1. 고차 함수는 왜 사용하나요?
A: 코드 재사용과 추상화!
// ❌ 중복 코드
fun getEvens(list: List<Int>) = list.filter { it % 2 == 0 }
fun getOdds(list: List<Int>) = list.filter { it % 2 != 0 }
// ✅ 고차 함수로 재사용
fun filterBy(list: List<Int>, condition: (Int) -> Boolean) =
list.filter(condition)
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
val evens = filterBy(numbers) { it % 2 == 0 }
val odds = filterBy(numbers) { it % 2 != 0 }
}
Q2. 언제 사용하면 좋나요?
A: 반복되는 패턴을 추상화할 때!
// 여러 곳에서 비슷한 작업
fun processUsers() {
// 로그 시작
println("처리 시작")
// 실제 작업
println("사용자 처리")
// 로그 종료
println("처리 완료")
}
// ✅ 고차 함수로 추상화
fun withLogging(action: () -> Unit) {
println("처리 시작")
action()
println("처리 완료")
}
fun main() {
withLogging {
println("사용자 처리")
}
}
Q3. 성능에 문제는 없나요?
A: 대부분 무시할 정도! 가독성이 더 중요합니다.
// 성능은 거의 같음
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// 일반 반복문
val result1 = mutableListOf<Int>()
for (num in numbers) {
if (num % 2 == 0) {
result1.add(num * 2)
}
}
// 고차 함수 (더 읽기 쉬움!)
val result2 = numbers
.filter { it % 2 == 0 }
.map { it * 2 }
}
🎬 마치며
고차 함수로 표현력 있는 코드를 작성하세요!
핵심 정리:
✅ 함수를 인자로 받거나 반환
✅ filter, map, reduce 등 활용
✅ 코드 재사용과 추상화
✅ 체이닝으로 깔끔한 처리
✅ 함수형 프로그래밍의 기초
다음 단계: 스코프 함수에서 let, apply 등을 알아보세요!