Table of contents
- Function Declaration
- Default Parameters
- Named Arguments
- Single-Expression Functions
- Extension Functions
Function Declaration
Kotlin functions are declared with the fun keyword.
fun greet(name: String): String {
return "Hello, $name!"
}
The return type comes after a colon. If there’s no return value, it’s Unit, which can be omitted. It corresponds to Java’s void.
fun log(message: String) { // : Unit is omitted
println(message)
}
Default Parameters
If you’ve ever overloaded methods excessively in Java, Kotlin’s default parameters will be a welcome change.
fun createUser(
name: String,
age: Int = 0,
role: String = "user"
): String {
return "$name ($age, $role)"
}
This single function supports multiple calling styles.
createUser("Kim") // Kim (0, user)
createUser("Lee", 25) // Lee (25, user)
createUser("Park", 30, "admin") // Park (30, admin)
In Java, you’d need a separate overloaded method for each parameter combination. Kotlin solves it with default values alone.
Named Arguments
When there are many parameters, it’s easy to get confused about which value corresponds to which parameter at the call site. Named arguments make this clear.
createUser(
name = "Kim",
role = "admin", // Skip age and specify only role
)
The key benefit is being able to skip intermediate parameters. Combined with default parameters, this enables flexible object creation without the builder pattern.
Single-Expression Functions
When a function body consists of a single expression, you can omit the curly braces and return.
// Regular form
fun double(x: Int): Int {
return x * 2
}
// Single expression — same function in one line
fun double(x: Int) = x * 2
The return type can also be inferred, so it can be omitted. This is commonly used for simple conversion and utility functions.
However, readability suffers when the logic gets complex, so it’s best used only when it fits naturally on a single line.
Extension Functions
One of Kotlin’s most distinctive features. You can add methods to existing classes without inheriting from or modifying them.
// Add an isEmail function to String
fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
fun main() {
println("test@email.com".isEmail()) // true
println("not-email".isEmail()) // false
}
Writing String.isEmail() lets you call it as if the method originally existed on the String class. this refers to the object the function was called on.
Here’s one more practical example.
// Add a Won (KRW) format to Int
fun Int.toWon(): String {
return "\u20a9${String.format("%,d", this)}"
}
fun main() {
println(50000.toWon()) // \u20a950,000
println(1234567.toWon()) // \u20a91,234,567
}
Extension functions cannot access private members of the original class. Internally, they compile to static methods, so they don’t break the encapsulation of the original class.
While they look like member methods at the call site, here’s how they’re actually transformed at the JVM bytecode level.
flowchart LR
Src["Syntax<br/>"abc".isEmail()"] --> Comp[Kotlin Compiler]
Comp --> Byte["JVM Bytecode<br/>StringUtilsKt.isEmail("abc")"]
Byte --> Note[Static method call]
Note --> Result[Result: Boolean]
This is especially useful when creating utility functions in Android development or Spring projects. Instead of StringUtils.isEmpty(str), you can write the more natural str.isEmpty().
The next part covers Kotlin classes and objects. We’ll see how much boilerplate data class eliminates and what role object plays.




Loading comments...