Spring
Basic
Kotlin 문법
코틀린 함수

Kotlin Functions

Single Expression Functions

1줄 함수는 다음과 같이 축약 가능

fun sum(x: Int, y: Int) = x + y
 
fun main() {
    println(sum(1, 2)) // 3
}

Lambda

  1. 람다식은 중괄호 안에 작성한다.
  2. 파라미터 뒤에 -\> 로 return 타입을 표시해준다.
  3. 중괄호의 끝나고 소괄호가 오는데 여기에는 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)
}