람다의 유용성과 생김세
코드에서 인련의 동작을 변수에 저장하거나 다른 함수에 저장해야 하는 경우가 더러 있음
예전 자바에서는 위의 경우들에 익명 내부 클래스를 사용했음
이 문제를 해결하는 접근 방법 : 함수를 값처럼 다루기
람다의 장점
버튼 클릭에 따른 동작을 정의하는 예제 (자바 익명 내부 클래스)
button.setOnClickListener(object: onClickListner {
override fun onClick(v: View) {
println("I was clicked!")
}
})
위 예제의 문제점
람다 사용을 통한 코드 개선
button.onClickListener {
println("I was clicked!")
}
data class Person(val name: String, val age: Int)
직접 구현하기
data class Person(val name: String, val age: Int)
fun findTheOldest(people: List<Person>) {
var maxAge = 0
var theOldest : Person? = null
for (person in people) {
if(person.age > maxAge) {
maxAge = person.age
theOldest = person
}
}
println(theOldest)
}
fun main() {
val people = listOf(Person("Alice", 29), Person("Bob", 31))
findTheOldest(people)
}
//Person(name=Bob, age=31)
표준 라이브러리 사용하기
data class Person(val name: String, val age: Int)
fun main() {
val people = listOf(Person("Alice", 29), Person("Bob", 31))
println(people.maxByOrNull { it.age })
}
//Person(name=Bob, age=31)
람다가 단순한 함수나 프로퍼티에 위임할 경우 맴버 참조를 사용할 수 있음
people.maxByOrNull (Person :: age)

람다식을 변수에 저장할 수 있음
fun main(){
val sum = { x: Int, y: Int -> x + y }
println(sum(1, 2))
}
// 3
람다식을 직접 호출할 수도 있음
fun main(){
{ println(42) }()
}
// 42
val myFavoriteNumber = run {
println("I'm thinking!")
println("I'm doing some more work...")
42
}암시적 인자를 사용하지 않고 정식으로 람다를 작성한 모습
people.maxByOrNull({ p: Person -> p.age })
중괄호 제거
people.maxByOrNull() { p: Person -> p.age }
괄호 제거
people.maxByOrNull {p: Person -> p.age}
여러 인자 중 마지막 인자만 람다인 경우 람다를 밖으로 빼는것이 바람직함
둘 이상의 람다를 인자로 받는 경우 람다를 괄호 밖으로 뺄 수 없음
data class Person(val name: String, val age: Int)
fun main() {
val people = listOf(Person("Alice", 29), Person("Bob", 31))
val names = people.joinToString(
separator = " ",
transform = { p: Person -> p.name }
)
println(names)
}
// Alice Bob
이 함수에서 람다를 괄호 밖으로 뺀 모습
people.joinToString(" ") { p: Person -> p.name }
파라미터 타입 제거하기
people.maxByOrNull {p: Person -> p.age} //파라미터 타입을 명시
people.maxByOrNull {p -> p.age} //파라미터 타입을 컴파일러가 추론
people.maxByOrNull { it.age }
val getAge = { p: Person -> p.age }
people.maxByOrNull(getAge)fun main() {
val sum = {x: Int, y: Int ->
println("Computing the sum of $x and $y...")
x + y
}
println(sum(1, 2))
}
fun printProblemCounts(response: Collection<String>) {
var clientErrors = 0
var serverErrors = 0
response.forEach {
if(it.startsWith("4"))
clientErrors++
else if (it.startsWith("5"))
serverErrors++
}
println("$clientErrors client errors, $serverErrors server errors")
}
fun main() {
val response = listOf("200 OK", "418 I'm teapot", "500 Internet Server Error")
printProblemCounts(response)
}
//1 client errors, 1 server errors
람다를 이벤트 핸들러나 비동기적으로 실행되는 코드로 활용하는 경우 로컬 변수 변경은 람다가 실행되는 동안에만 이뤄짐
fun tryToCountButtonClicks(button : Button): Int {
var clicks = 0
button.onClick { clicks++ }
return clicks
}
넘기려는 코드가 이미 함수로 선언된 경우?
val getAge = Person :: age
// val getAge = { p: Person -> p.age }와 기능이 같음

fun salute() = println("Salute!")
fun main() {
run(::salute)
}
//Salute!
val action = {person: Person, message: String -> // sendEmail에 작업 위임
sendEmail(person, message)
}
val nextAction = :: sendEmail // 람다 대신 맴버 참조를 쓸 수 있음
fun main() {
val createPerson = ::Person
val p = createPerson("Alice", 29)
println(p)
}
fun Person.isAdult() = age >= 21
val predicate = Person::isAdult
fun main() {
val seb = Person("Sebastian", 26)
val personAgeFunction = Person::age //Person이 주어지면 나이를 돌려주는 맴버 참조
println(personAgeFunction(seb)) //사람을 인자로 받음
//26
val sebAgeFunction = seb::age // 특정 사람의 나이를 돌려주는, 값과 엮인 호출 가능 참조
println(sebAgeFunction()) // 특정 값과 엮여있기 때문에 아무 파라밑를 지정하지 않아도 됨
//26
}