: 내부 익명 클래스를 사용
button.setOnClickListner(new OnClickListener() {
@Override
public void onClick(View view) {
//
}
}
→ 코드가 번잡스럽고, 이런 작업을 여러번 수행해야 하는 경우엔..
→ 일회용 클래스
: 함수를 값처럼 다루자!
button.setOnClickListner{ // }
data class Person(val name: String, val age: Int) {
companion object {}
}
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", 24), Person("Carol", 39))
findTheOldest(people)
}
data class Person(val name: String, val age: Int) {
companion object {}
}
fun main() {
val people = listOf(Person("Alice", 29), Person("Bob", 24), Person("Carol", 39))
println(people.maxByOrNull{ it.age })
println(people.maxByOrNull(Person::age))
}
→ 책에는 maxBy()로 나오는데 이건 deprecated
→ 람다나 멤버 참조를 사용해서 더 짧고 가독성 좋게 개선
val sum = { x: Int, y: Int -> x + y }
println(sum(1, 2))
: 코드의 일부분을 블록으로 둘러싸서 실행이 필요한 경우
val num = 42
num.run { println(this) }
→ 기본 람다를 언제 사용해야 할지?
https://medium.com/@limgyumin/코틀린-의-apply-with-let-also-run-은-언제-사용하는가-4a517292df29
https://kotlinlang.org/docs/scope-functions.html#function-selection
people.maxByOrNull({ p: Person -> p.age })
people.maxByOrNull(){ p: Person -> p.age }
people.maxByOrNull { p: Person -> p.age }
people.maxByOrNull{ it.age } // 제일 익숙한 형태
→ 코틀린에서 맨 뒤의 인자가 람다면 밖으로 뺄 수 있고, 다른 인자가 없으면 () 생략 가능
를 활용해보자
val name = people.joinToString(separator = " ", transform = {p->p.name})
val name = people.joinToString(" "){ p->p.name }
코틀린 컴파일러가 자동으로 파라미터 타입을 추론하여 굳이 명시하지 않아도 되지만, 변수에 저장할때는 타입 추론 문맥이 없어서 명시해야됨
val getAge = { p: Person -> p.age }
fun printMessageWithPrefix(responses: Collection<String>, prefix: String) {
var clientErrors = 0
var serverErrors = 0
responses.forEach {
if (it.startsWith("4")) clientErrors++
else if (it.startsWith("5")) serverErrors++
}
println("$prefix $clientErrors client errors, $prefix $serverErrors server errors")
}
fun main() {
val errors = listOf("401 Unauthorized", "404 Not Found", "200 Ok", "500 Internal Server Error")
printMessageWithPrefix(errors, "Errors:")
}
class Button {
fun onClick(function: () -> Int) {
function()
}
}
fun tryToCountButtonClicks(button: Button): Int {
var clicks = 0
button.onClick{ clicks++ }
return clicks
}
fun main() {
val button = Button()
val clickNum = tryToCountButtonClicks(button)
println(clickNum)
}
→ 책에서의 설명(tryToCountButtonClicks가 clicks를 반환 한 다음 tryToCountButtonClicks이 호출되어 항상 0이 반환된다고 하는데 실제로 디버깅하면 반환 전에 onClick()이 먼저 호출된 다음 반환이 된다. 따라서 위와 같이 실행하면 1이 출력되는데 요건 번역 오류인지 무슨 의미인지 잘 모르겠다
people.maxByOrNull{ it.age }
→ 최상위에 선언된 함수나 프로퍼티도 참조 가능하다
fun salute() = println("salute!")
fun main() {
run(::salute)
}
: 직접 위임 함수에 대한 참조 제공하면 편함
fun sendEmail(person: Person, message: String) {
println("${person.name} sent $message")
}
fun main() {
val action1 = {
person: Person, message: String -> sendEmail(person, message)
}
val action2 = ::sendEmail //람다 대신 멤버 참조 사용
action1(Person("leean", 25), "hi")
action2(Person("leean", 25), "hi")
}
val list = listOf(1, 2, 3, 4)
println(list.filter { it%2 == 0 })
→ 컬렉션에서 원하는 원소만 필터해서 새 컬렉션 반환
val list = listOf(1, 2, 3, 4)
println(list.filter { it%2 == 0 })
→ 컬렉션에서 주워진 람다를 각 컬렉션에 적용한 결과를 새 컬렉션으로 반환
// 위의 코드에서 불필요한 연산 제거하기
val maxAge = people.maxBy(Person::age)!!.age
people.filter{ it.age == maxAge }
val canBeInClub27 = { p:Person -> p.age <= 27 }
val people = listOf(Person("Alice", 27), Person("Bob", 25), Person("Carol", 37))
println(people.all(canBeInClub27))
println(people.any(canBeInClub27))
println(people.count(canBeInClub27))
println(people.find(canBeInClub27))
>>> false
>>> true
>>> 2
>>> Person(name=Alice, age=27)
원소를 특성에 따라 그룹으로 나누기
val people = listOf(Person("Alice", 27), Person("Bob", 25), Person("Carol", 27))
println(people.groupBy { it.age })
>>> {27=[Person(name=Alice, age=27), Person(name=Carol, age=27)], 25=[Person(name=Bob, age=25)]}
→ 결과: Map<Int, List>
→ db에서 인덱스 타더라도 groupBy/aggregate 때문에 slow가 발생하는경우가 왕왕 있다 → 메모리에 올려놔도 상관없는 경우에 app단에서 groupBy를 사용하는게 더 빠른 경우가 있다
인자로 주어진 람다를 컬렉션 모든 객체에 매핑
data class Book(val title: String, val author: List<String>) {
companion object
}
fun main() {
val books = listOf(
Book("kotlin in action", listOf("rein", "moka", "leean")),
Book("modern java in action", listOf("jace", "dante", "moka"))
)
println(books.flatMap { it.author }.toSet())
}
특별히 매핑이 필요 없는 경우
외에 더 많은 API는 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-collection/#kotlin.collections.Collection 를 참고하자~!
→ 람다 안에 뭔가 로직이 복잡하다,,? 중첩된다? 싶으면 바로 검색