Kotlin Functions
Single Expression Functions
1줄 함수는 다음과 같이 축약 가능
fun sum(x: Int, y: Int) = x + y
fun main() {
println(sum(1, 2)) // 3
}
Lambda
- 람다식은 중괄호 안에 작성한다.
- 파라미터 뒤에
-\>
로 return 타입을 표시해준다. - 중괄호의 끝나고 소괄호가 오는데 여기에는 argument를 넣는다.
fun main() {
println({ string: String -> string.uppercase() }) // HELLO
}
void
kotlin에서는 void 대신 Unit
이라는 타입을 사용한다.
함수의 매개변수로 사용
filter
fun main() {
val numbers = listOf(1, -2, 3, -4, 5, -6)
val positives = numbers.filter { x -> x > 0 }
val negatives = numbers.filter { x -> x < 0 }
println(positives) // [1, 3, 5]
println(negatives) // [-2, -4, -6]
}
map
fun main() {
var numbers: List<Int> = listOf(1, 2, 3, 4, 5)
var squareOfNumbers: List<Int> = numbers.map { it * it }
println(squareOfNumbers) /// [1, 4, 9, 16, 25]
}
함수에서 람다 반환
아래 코드는 toSeconds 함수가 lambda를 반환하는 코드이며 10번 라인의 min2sec에서 lambda를 받아서 map에 적용하는 코드이다.
fun toSeconds(time: String): (Int) -> Int = when (time) {
"hour" -> { value -> value * 60 * 60 }
"minute" -> { value -> value * 60 }
"second" -> { value -> value }
else -> { value -> value }
}
fun main() {
val timesInMinutes = listOf(2, 10, 15, 1)
val min2sec = toSeconds("minute")
val totalTimeInSeconds = timesInMinutes.map(min2sec).sum()
println("Total time is $totalTimeInSeconds secs")
// Total time is 1680 secs
}
고차 함수(Higher Order Function)
다른 함수가 인자로 들어가는 함수를 고차 함수라고 한다. 고차 함수의 인자로 들어가는 함수는 ()안에 있어야 하지만 마지막 인자로 들어가는 경우 () 밖에 있어도 된다.
fun printDivisor(value: Int, printer: (Int) -> Unit) {
for (i in 1..value) {
if (value % i == 0) {
printer(i)
}
}
}
fun main() {
printDivisor(10) { value ->
println(value)
}
}
확장 함수
fun main() {
val userEntity = UserEntity(name = "홍길동", age = 20)
userEntity.sayName()
}
fun UserEntity.sayName() {
println(this.name)
}
class UserEntity(var name: String = "홍길동", var age: Int = 10)
표준 함수
let
let 구문 안에 나오는 맨마지막 값이 return 된다.
.let은 기본적으로 it
이라는 지역변수를 사용하게 되고 .let 안에는 null 값이 들어오지 못하기 때문에 null 체크를 할 필요가 없다
.
⚠️
return을 사용하면 에러가 발생한다.
fun main() {
var a: String? = "Hello World"
a = a?.let {
"A is Not Null"
}
println(a) /// A is Not Null
UserEntity("John", 20, "Seoul").let { userEntity ->
println(userEntity.name)
println(userEntity.age)
println(userEntity.address)
}
}
class UserEntity(val name: String, val age: Int, val address: String)
also
구문안에서 어떠한 변화가 일어나던지 처음에 넘겨받은 값을 return 한다.
fun main() {
var userEntity = UserEntity(name = "홍길동").also {
UserEntity("청길동")
}
/// 만약에 let을 사용했다면 맨마지막 값이 return 되기 때문에 청길동이 출력
/// also라서 처음에 넘겨받은 값을 return
println(userEntity.name) /// 홍길동
userEntity = UserEntity(name = "홍길동").let{
UserEntity("청길동")
}
println(userEntity.name) /// 청길동
}
class UserEntity(var name: String)
apply
코틀린의 Builder 패턴이라고 생각하면 된다.
fun main() {
val userEntity = UserEntity().apply {
this.name = "김철수"
this.age = 20
}
/// 김철수는 20살이다.
println(userEntity.name + "는 " + userEntity.age + "살이다.")
}
class UserEntity(var name: String = "홍길동", var age: Int = 10)
run
지역 스코프를 만들어주기 위해서 사용하며, 맨 마지막에 라인에 있는 값이 return 된다.
fun main() {
val userEntity = UserEntity(name = "한국영", age=1000).run {
UserEntity()
}
/// 홍길동 10
println(userEntity.name + " " + userEntity.age)
var x = 10
/// run 안의 값은 지역변수이므로 위에 있는 x 값에는 영향 X
val sum = run {
val x = 2
val y = 3
x + y
}
println(x) /// 10
}
class UserEntity(var name: String = "홍길동", var age: Int = 10)
어떠한 로직을 넣어야 되는데 scope가 필요할 때 run을 또 사용할 수 있다.
fun main() {
val now: LocalDateTime? = null
/// 이렇게 추가적으로 들어가야 할 로직이 없을 때는
/// run을 사용하지 않고 한 줄로 간결하게 표현가능
val n = now?.let {
it
}?: LocalDateTime.now()
/// 이렇게 뭔가 여러 줄 이상의 로직이 들어가야 할 때는
/// run을 사용해서 scope를 만들어준다
val n2 = now?.let {
val minusDay = it.minusDays(1)
minusDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
}?: run {
val minusDay = LocalDateTime.now().minusDays(1)
minusDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
}
println(n)
}