2025년 12월 31일 작성
Kotlin 함수 - fun, Default Parameter, Named Argument
Kotlin 함수는 fun keyword로 선언하며, default parameter, named argument, 단일 표현식 함수 등 간결한 문법을 제공합니다.
함수 선언
- Kotlin은
funkeyword로 함수를 선언합니다.- parameter는
이름: type형식으로 작성합니다. - return type은 parameter 뒤에
: type으로 명시합니다.
- parameter는
fun add(a: Int, b: Int): Int {
return a + b
}
fun greet(name: String): String {
return "Hello, $name!"
}
- 반환값이 없는 함수는
Unit을 반환합니다.Unit은 생략할 수 있습니다.
fun printMessage(message: String): Unit {
println(message)
}
// Unit 생략
fun printMessage(message: String) {
println(message)
}
단일 표현식 함수
- 함수 본문이 단일 표현식이면
=로 간결하게 작성할 수 있습니다.- 중괄호와
return을 생략합니다. - return type도 추론 가능하면 생략할 수 있습니다.
- 중괄호와
fun add(a: Int, b: Int): Int = a + b
// return type 추론
fun add(a: Int, b: Int) = a + b
fun greet(name: String) = "Hello, $name!"
fun max(a: Int, b: Int) = if (a > b) a else b
- 함수가 복잡해지면 명시적 return type을 권장합니다.
- public API의 경우 return type을 명시하는 것이 좋습니다.
Default Parameter
- default parameter(기본 매개 변수)는 parameter에 기본값을 지정하는 기능입니다.
- 함수 호출 시 해당 인자를 생략할 수 있습니다.
- Java의 method overloading을 대체합니다.
fun createUser(
name: String,
age: Int = 0,
active: Boolean = true
) {
println("$name, $age, $active")
}
// 호출
createUser("Kim") // Kim, 0, true
createUser("Lee", 25) // Lee, 25, true
createUser("Park", 30, false) // Park, 30, false
- default parameter는 뒤쪽에 배치하는 것이 좋습니다.
- 앞쪽에 있으면 named argument를 사용해야 합니다.
Named Argument
- parameter 이름을 지정하여 인자를 전달할 수 있습니다.
- 순서에 관계없이 원하는 parameter에 값을 전달할 수 있습니다.
- code 가독성이 높아집니다.
fun createUser(name: String, age: Int, active: Boolean) {
// ...
}
// named argument 사용
createUser(name = "Kim", age = 25, active = true)
// 순서 변경 가능
createUser(active = false, name = "Lee", age = 30)
// 일부만 named argument 사용
createUser("Park", age = 28, active = true)
- default parameter와 함께 사용하면 유연한 호출이 가능합니다.
fun sendEmail(
to: String,
subject: String = "No Subject",
body: String = "",
cc: String? = null
) {
// ...
}
sendEmail(to = "user@example.com")
sendEmail(to = "user@example.com", body = "Hello!")
sendEmail(to = "user@example.com", cc = "admin@example.com")
Vararg
- 가변 인자를 받을 때
varargkeyword를 사용합니다.- 0개 이상의 인자를 배열로 받습니다.
- 함수당 하나의
vararg만 사용할 수 있습니다.
fun printAll(vararg messages: String) {
for (message in messages) {
println(message)
}
}
printAll("Hello", "World", "Kotlin")
printAll() // 인자 없이 호출 가능
- spread operator (
*)로 배열을 펼쳐서 전달할 수 있습니다.
val items = arrayOf("A", "B", "C")
printAll(*items) // spread operator
// 다른 인자와 함께 사용
printAll("Start", *items, "End")
vararg가 마지막 parameter가 아닌 경우 named argument가 필요합니다.
fun format(vararg values: String, separator: String): String {
return values.joinToString(separator)
}
// named argument 필요
format("A", "B", "C", separator = ", ")
Local Function
- 함수 내부에 함수를 정의할 수 있습니다.
- 외부 함수의 변수에 접근할 수 있습니다.
- 특정 함수 내에서만 사용되는 logic을 캡슐화합니다.
fun processUser(user: User) {
// local function
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("$fieldName is empty")
}
}
validate(user.name, "Name")
validate(user.email, "Email")
// 처리 logic
}
- local function은 외부 함수의 변수를 capture할 수 있습니다.
- Java와 달리
var변수도 capture하고 수정할 수 있습니다.
- Java와 달리
fun printProgress(items: List<String>) {
var count = 0
fun printItem(item: String) {
count++ // 외부 변수 capture 및 수정
println("[$count] $item")
}
for (item in items) {
printItem(item)
}
}
printProgress(listOf("A", "B", "C"))
// [1] A
// [2] B
// [3] C
Infix Function
infixkeyword로 중위 표기법을 사용할 수 있습니다.- member function 또는 extension function이어야 합니다.
- parameter가 정확히 하나여야 합니다.
- 기본값이나 vararg를 사용할 수 없습니다.
infix fun Int.times(str: String) = str.repeat(this)
// 중위 표기법 호출
val result = 3 times "Hello " // "Hello Hello Hello "
// 일반 호출도 가능
val result2 = 3.times("Hi ")
- 표준 library의 infix function 예시입니다.
// to : Pair 생성
val pair = "key" to "value"
// until : 범위 생성 (마지막 값 제외)
for (i in 0 until 10) { }
// downTo : 역순 범위
for (i in 10 downTo 1) { }
// step : 증가값
for (i in 0 until 10 step 2) { }
Operator Overloading
operatorkeyword로 연산자를 재정의할 수 있습니다.- 정해진 이름의 함수를 정의하면 해당 연산자로 호출할 수 있습니다.
| 연산자 | 함수 이름 |
|---|---|
+ |
plus |
- |
minus |
* |
times |
/ |
div |
% |
rem |
== |
equals |
<, > |
compareTo |
[] |
get, set |
() |
invoke |
in |
contains |
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
operator fun times(scale: Int) = Point(x * scale, y * scale)
}
val p1 = Point(1, 2)
val p2 = Point(3, 4)
val p3 = p1 + p2 // Point(4, 6)
val p4 = p1 * 3 // Point(3, 6)
- 복합 대입 연산자(compound assignment operator)도 정의할 수 있습니다.
data class Counter(var value: Int) {
operator fun plusAssign(amount: Int) {
value += amount
}
}
val counter = Counter(0)
counter += 5 // counter.value = 5
Tailrec
tailreckeyword로 꼬리 재귀 최적화를 적용할 수 있습니다.- compiler가 재귀를 loop로 변환하여 stack overflow를 방지합니다.
- 재귀 호출이 함수의 마지막 동작이어야 합니다.
tailrec fun factorial(n: Long, accumulator: Long = 1): Long {
return if (n <= 1) {
accumulator
} else {
factorial(n - 1, n * accumulator) // 꼬리 위치
}
}
println(factorial(10000)) // stack overflow 없이 계산
- 꼬리 위치가 아닌 경우 compiler 경고가 발생합니다.
// 꼬리 재귀 아님 : 재귀 호출 후 곱셈 연산
tailrec fun badFactorial(n: Long): Long {
return if (n <= 1) 1
else n * badFactorial(n - 1) // 경고 발생
}
Java와의 비교
- Kotlin 함수는 Java method보다 간결하고 유연합니다.
// Java : method overloading 필요
public void createUser(String name) {
createUser(name, 0, true);
}
public void createUser(String name, int age) {
createUser(name, age, true);
}
public void createUser(String name, int age, boolean active) {
// ...
}
// Kotlin : default parameter로 해결
fun createUser(
name: String,
age: Int = 0,
active: Boolean = true
) {
// ...
}
| Java | Kotlin | 설명 |
|---|---|---|
| method overloading | default parameter | 선택적 인자 |
| Builder pattern | named argument | 가독성 높은 호출 |
void |
Unit |
반환값 없음 |
| N/A | 단일 표현식 함수 | 간결한 함수 정의 |
| N/A | tailrec |
꼬리 재귀 최적화 |