본문으로 건너뛰기 Kotlin 함수 | 함수 정의, 람다, 고차 함수

Kotlin 함수 | 함수 정의, 람다, 고차 함수

Kotlin 함수 | 함수 정의, 람다, 고차 함수

이 글의 핵심

Kotlin 함수: 함수 정의, 람다, 고차 함수. 함수 정의·람다식.

들어가며

함수는 일급 객체로 다루어져, 변수에 담고 고차 함수의 인자로 넘기기 쉽습니다. 람다·익명 함수 문법이 짧아, 컬렉션 연산과 잘 맞습니다.

1. 함수 정의

기본 함수

Kotlin 함수의 기본 형태입니다:

// 1. 반환값 없는 함수
fun greet(name: String) {
    // fun: 함수 선언 키워드
    // greet: 함수 이름
    // (name: String): 매개변수 (이름: 타입)
    // 반환 타입 생략 시 Unit (void와 유사)
    println("안녕하세요, $name님!")
    // $name: 문자열 템플릿 (변수 삽입)
}
greet("홍길동")  // 안녕하세요, 홍길동님!
// 2. 반환값 있는 함수 (블록 본문)
fun add(a: Int, b: Int): Int {
    // : Int : 반환 타입 명시 (필수)
    return a + b
    // return 키워드로 값 반환
}
val result = add(10, 20)
println(result)  // 30
// 3. 표현식 함수 (단일 표현식)
fun add(a: Int, b: Int) = a + b
// = 뒤에 표현식 작성
// 반환 타입 자동 추론 (Int)
// return 키워드 불필요
// 간결하고 읽기 쉬움
// 표현식 함수 예시
fun max(a: Int, b: Int) = if (a > b) a else b
fun square(x: Int) = x * x
fun isEven(x: Int) = x % 2 == 0
println(max(10, 20))   // 20
println(square(5))     // 25
println(isEven(4))     // true
// 4. Unit 반환 (명시적)
fun printSum(a: Int, b: Int): Unit {
    // Unit: 반환값이 없음을 명시 (생략 가능)
    // Java의 void와 유사하지만 실제로는 싱글톤 객체
    println(a + b)
    // return 생략 가능 (자동으로 Unit 반환)
}
// Unit 생략 (권장)
fun printSum(a: Int, b: Int) {
    println(a + b)
}

함수 선언 위치:

// 최상위 함수 (파일 레벨)
fun topLevel() {
    println("최상위 함수")
}
class MyClass {
    // 멤버 함수 (클래스 내부)
    fun memberFunction() {
        println("멤버 함수")
    }
    
    // 지역 함수 (함수 내부)
    fun outer() {
        fun inner() {
            println("지역 함수")
        }
        inner()  // 지역 함수 호출
    }
}

기본 매개변수

fun greet(name: String = "Guest", greeting: String = "안녕하세요") {
    println("$greeting, $name님!")
}
greet()                          // 안녕하세요, Guest님!
greet("홍길동")                  // 안녕하세요, 홍길동님!
greet("홍길동", "Hello")         // Hello, 홍길동님!
greet(greeting = "Hi")           // Hi, Guest님!

가변 인자

// 실행 예제
fun sum(vararg numbers: Int): Int {
    return numbers.sum()
}
println(sum(1, 2, 3))        // 6
println(sum(1, 2, 3, 4, 5))  // 15
// 배열 전달
val nums = intArrayOf(1, 2, 3)
println(sum(*nums))  // spread 연산자

2. 람다식

기본 문법

// 람다 정의
val sum = { a: Int, b: Int -> a + b }
println(sum(10, 20))  // 30
// 타입 추론
val multiply: (Int, Int) -> Int = { a, b -> a * b }
// 단일 매개변수 (it)
val square: (Int) -> Int = { it * it }
println(square(5))  // 25

람다 활용

Kotlin의 컬렉션 함수와 람다를 함께 사용하는 예제입니다:

val numbers = listOf(1, 2, 3, 4, 5)
// 1. filter: 조건에 맞는 요소만 선택
val evens = numbers.filter { it % 2 == 0 }
// { it % 2 == 0 }: 람다 표현식
// it: 암묵적 매개변수 (단일 매개변수일 때 사용)
// it % 2 == 0: 짝수 판별 조건
// 
// 동작:
// 1 → false (제외)
// 2 → true (포함)
// 3 → false (제외)
// 4 → true (포함)
// 5 → false (제외)
println(evens)  // [2, 4]
// 명시적 매개변수 사용
val evens2 = numbers.filter { num -> num % 2 == 0 }
// num: 명시적 매개변수 이름
// it 대신 의미 있는 이름 사용 가능
// 2. map: 각 요소를 변환
val doubled = numbers.map { it * 2 }
// 각 요소에 2를 곱함
// [1, 2, 3, 4, 5] → [2, 4, 6, 8, 10]
println(doubled)  // [2, 4, 6, 8, 10]
// map 실전 예시: 객체 변환
data class User(val name: String, val age: Int)
val users = listOf(
    User("홍길동", 25),
    User("김철수", 30)
)
val names = users.map { it.name }
println(names)  // [홍길동, 김철수]
// 3. forEach: 각 요소에 대해 작업 수행 (반환값 없음)
numbers.forEach { println(it) }
// 출력:
// 1
// 2
// 3
// 4
// 5
// forEach는 반환값이 없으므로 체이닝 불가
// map/filter와 달리 부수 효과(side effect)를 위해 사용
// 4. reduce: 배열을 하나의 값으로 축약
val sum = numbers.reduce { acc, num -> acc + num }
// acc: 누적값 (accumulator)
// num: 현재 요소
// 
// 동작:
// acc=1 (첫 요소), num=2 → 1+2=3
// acc=3, num=3 → 3+3=6
// acc=6, num=4 → 6+4=10
// acc=10, num=5 → 10+5=15
println(sum)  // 15
// fold: 초기값 지정 가능
val sum2 = numbers.fold(0) { acc, num -> acc + num }
// 0: 초기값
// reduce는 첫 요소가 초기값, fold는 명시적 초기값
// 실전 예시: 문자열 연결
val words = listOf("Hello", "World", "Kotlin")
val sentence = words.reduce { acc, word -> "$acc $word" }
println(sentence)  // Hello World Kotlin

체이닝 예제:

val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val result = numbers
    .filter { it % 2 == 0 }      // 짝수만: [2, 4, 6, 8, 10]
    .map { it * it }             // 제곱: [4, 16, 36, 64, 100]
    .filter { it > 20 }          // 20 초과: [36, 64, 100]
    .sum()                       // 합계: 200
println(result)  // 200

3. 고차 함수

함수를 매개변수로

fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}
val result1 = calculate(10, 5) { a, b -> a + b }  // 15
val result2 = calculate(10, 5) { a, b -> a * b }  // 50

함수를 반환

fun makeMultiplier(factor: Int): (Int) -> Int {
    return { number -> number * factor }
}
val double = makeMultiplier(2)
val triple = makeMultiplier(3)
println(double(5))  // 10
println(triple(5))  // 15

4. 확장 함수

기본 확장

// String에 함수 추가
fun String.addExclamation() = "$this!"
println("Hello".addExclamation())  // Hello!
// Int에 함수 추가
fun Int.isEven() = this % 2 == 0
println(4.isEven())   // true
println(5.isEven())   // false

실전 확장 함수

// List 확장
fun <T> List<T>.secondOrNull(): T? {
    return if (size >= 2) this[1] else null
}
val list = listOf(1, 2, 3)
println(list.secondOrNull())  // 2
// String 확장
fun String.isValidEmail(): Boolean {
    return matches(Regex("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"))
}
println("test@example.com".isValidEmail())  // true

5. 스코프 함수

let

val name: String? = "홍길동"
name?.let {
    println("이름: $it")
    println("길이: ${it.length}")
}

apply

// 실행 예제
data class Person(var name: String = "", var age: Int = 0)
val person = Person().apply {
    name = "홍길동"
    age = 25
}

also

val numbers = mutableListOf(1, 2, 3)
    .also { println("초기 리스트: $it") }
    .also { it.add(4) }
    .also { println("최종 리스트: $it") }

run

// 실행 예제
val result = "Hello".run {
    println(this)
    length
}
println(result)  // 5

with

val person = Person("홍길동", 25)
with(person) {
    println(name)
    println(age)
}

6. 인라인 함수

kotlin 예제 코드입니다.

inline fun measureTime(block: () -> Unit) {
    val start = System.currentTimeMillis()
    block()
    val end = System.currentTimeMillis()
    println("실행 시간: ${end - start}ms")
}
measureTime {
    Thread.sleep(1000)
}

7. 실전 예제

예제 1: 함수형 프로그래밍

data class User(val name: String, val age: Int, val city: String)
fun main() {
    val users = listOf(
        User("홍길동", 25, "서울"),
        User("김철수", 30, "부산"),
        User("이영희", 28, "서울"),
        User("박민수", 35, "서울")
    )
    
    // 서울에 사는 30세 미만 사용자
    val result = users
        .filter { it.city == "서울" }
        .filter { it.age < 30 }
        .map { it.name }
    
    println(result)  // [홍길동, 이영희]
}

예제 2: DSL 스타일

class HTML {
    private val content = StringBuilder()
    
    fun head(block: () -> Unit) {
        content.append("<head>")
        block()
        content.append("</head>")
    }
    
    fun body(block: () -> Unit) {
        content.append("<body>")
        block()
        content.append("</body>")
    }
    
    override fun toString() = content.toString()
}
fun html(block: HTML.() -> Unit): HTML {
    return HTML().apply(block)
}
val page = html {
    head { }
    body { }
}

정리

핵심 요약

  1. 함수: fun, 표현식 함수, 기본 매개변수
  2. 람다: { a, b -> a + b }, it
  3. 고차 함수: 함수를 매개변수/반환
  4. 확장 함수: 기존 클래스에 함수 추가
  5. 스코프 함수: let, apply, also, run, with

다음 단계


관련 글


자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Kotlin 함수: 함수 정의, 람다, 고차 함수. 함수 정의·람다식로 흐름을 잡고 원리·코드·실무 적용을 한글로 정리합니다. Kotlin·함수·람다 중심으로 설명합니다. Start now. 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. Kotlin 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

Kotlin, 함수, 람다, 고차함수 등으로 검색하시면 이 글이 도움이 됩니다.