코틀린 (Kotlin) 람다 문법
코틀린 람다 문법
코틀린 람다는 자바의 람다와 비슷하지만 문법이 조금 다릅니다.{ x: Int, y:Int -> x+y} 처럼 블럭({..}) 안에 파라메터와 -> 를 구분자로해서 본문을 작성할 수 있습니다.
그리고 람다를 변수에 저장할 수 있습니다.
val sum = { x: Int, y:Int -> x+y} //람다식을 변수에 저장
//사용
sum(1,2)
//풀어쓴 람다
people.maxBy({ p : Person -> p.age})
//맨 뒤에 있는 인자가 람다 식인경우 밖으로 뺄 수 있다
people.maxBy() {
p : Person -> p.age
}
//람다가 유일한 인자인경우 괄호 생략 가능
people.maxBy {
p : Person -> p.age
}
//사용
sum(1,2)
//풀어쓴 람다
people.maxBy({ p : Person -> p.age})
//맨 뒤에 있는 인자가 람다 식인경우 밖으로 뺄 수 있다
people.maxBy() {
p : Person -> p.age
}
//람다가 유일한 인자인경우 괄호 생략 가능
people.maxBy {
p : Person -> p.age
}
아래 코드는 파라메터가 두개 이상이고 마지막 하나만 람다인 경우입니다.
people.joinToString(" ") { p: Person -> p.name } //마지막 람다를 블럭밖으로 뺌
람다 파라미터에서 타입을 제거할 수 있습니다.
//파라미터 타입 명시
people.maxBy { p:Person -> p.age }
//파라미터 타입 추론(컴파일러가 추론)
people.maxBy { p -> p.age }
people.maxBy { p:Person -> p.age }
//파라미터 타입 추론(컴파일러가 추론)
people.maxBy { p -> p.age }
람다의 파라미터가 하나이고 컴파일러가 타입을 추론할 수 있는 경우 it 을 사용할 수 있습니다.
//it 사용 : 람다의 파라미터가 하나인경우 컴파일러가 추론 가능
//중첩된 람다에서는 it 보다는 파라미터를 명시하는 것이 좋다
people.maxBy { it.age }
//중첩된 람다에서는 it 보다는 파라미터를 명시하는 것이 좋다
people.maxBy { it.age }
람다를 변수에 저장할 때는 타입을 추론할 수 없기때문에 타입을 명시해야 됩니다.
//람다를 변수에 저장할때는 추론할수 없기때문에 파라미터를 명시한다
val getAge = { p:Person -> p.age }
people.maxBy(getAge)
val getAge = { p:Person -> p.age }
people.maxBy(getAge)
람다 블럭의 마지막에 있는 식이 리턴되는 결과값이 됩니다.
val sum = { x:Int, y:Int ->
x+y //마지막 식이 리턴
}
sum(1,2) // 3이 리턴 됨
x+y //마지막 식이 리턴
}
sum(1,2) // 3이 리턴 됨
함수안에 내부 클래스를 정의할 경우 내부 클래스에서 함수의 파라메터를 접근해야되는 경우 final 이 되야합니다.
람다에서는 final 을 붙이지 않습니다.
람다는 모든 참조를 래퍼로 감싸서 읽고 쓸수 있도록 람다 코드와 함께 저장되기 때문입니다.
람다는 함수의 파라메터와 로컬 변수까지 래퍼로 감싸집니다.
val errors = listOf("403", "404")
fun printMessageWithPrefix(messages: Collection, prefix: String) {
messages.forEach { //람다식을 파라메터로 받는 forEach 함수
L.d("$prefix: $it") //파라메터 접근($prefix)
}
}
fun printProblemCount(responses: Collection) {
var clientErros = 0
var serverErrors = 0
responses.forEach {
if (it.startsWith("4")) {
clientErros++ //로컬 변수 수정
} else if (it.startsWith("5")) {
serverErrors++ //로컬 변수 수정
}
}
}
fun printMessageWithPrefix(messages: Collection
messages.forEach { //람다식을 파라메터로 받는 forEach 함수
L.d("$prefix: $it") //파라메터 접근($prefix)
}
}
fun printProblemCount(responses: Collection
var clientErros = 0
var serverErrors = 0
responses.forEach {
}
보통 로컬 변수는 함수 실행이 종료되면 해제됩니다.
그러나 람다를 변수에 저장할 경우에는 람다식이 로컬 변수를 래핑하기 때문에 해재되지 않고 존재합니다.
그러나 아래 코드처럼 click을 바로 리턴하면 onClick에서 clicks++ 해도 이미 click 이 리턴됬기때문에 항상 0을 리턴합니다.
fun tryToCountButtonClicks(button: Button): Int {
var clicks = 0
button.setOnClickListener {
//clicks 는 return 된후 onClick에 의해 clicks가 증가되기때문에 clicks 는 0 임
clicks++
}
return clicks
}
var clicks = 0
button.setOnClickListener {
//clicks 는 return 된후 onClick에 의해 clicks가 증가되기때문에 clicks 는 0 임
clicks++
}
return clicks
}
멤버참조
코틀린에서 :: 를 사용해서 프로퍼티나 메소드를 참조해서 값으로 저장할 수 있습니다.
people.maxby(Person::age) //멤버참조
people.maxby { p -> p.age } //람다로 풀어쓴 경우
people.maxBy { it.age } //람다로 간략하게 사용한 경우
//최상위 함수, 프로퍼티 참조
fun salute() = L.d(">>>")
run(::salute) //run함수에 참조 전달
//람다 대신 멤버 참조
val nextAction = :: salute
//생성자 참조
data class Person(val name: String, val age: Int)
val p = ::Person //생성자 참조
val person = p("zerog", 20)
fun constructorFunc(twoargs : (String, Int) -> Person) {
val p = twoargs("zerog", 10)
}
constructorFunc(::Person)
//확장 함수 참조
fun Person.isAdult() = age>=20
val predicate = Person::isAdult
people.maxby { p -> p.age } //람다로 풀어쓴 경우
people.maxBy { it.age } //람다로 간략하게 사용한 경우
//최상위 함수, 프로퍼티 참조
fun salute() = L.d(">>>")
run(::salute) //run함수에 참조 전달
//람다 대신 멤버 참조
val nextAction = :: salute
//생성자 참조
data class Person(val name: String, val age: Int)
val p = ::Person //생성자 참조
val person = p("zerog", 20)
fun constructorFunc(twoargs : (String, Int) -> Person) {
val p = twoargs("zerog", 10)
}
constructorFunc(::Person)
//확장 함수 참조
fun Person.isAdult() = age>=20
val predicate = Person::isAdult
자바 메소드에 코틀린 람다식 넘기기
일반적으로 자바에 객체 식을 넘길때는 obejct 를 사용합니다.
//Runable 를 인자로 받는 postponeComputation(int delay, Runnable run) 함수가 있음
val ramdaJava = RamdaJava()
//프로그램 전체에서 Runnable의 인스턴스는 단 하나만 생성
for (i in 1..3) {
ramdaJava.postponeComputation(100) {
L.d("run") //인자 포획 없음
}
}
//메소드를 호출할때마다 object 가 새로 생성된다
for (i in 1..3) {
ramdaJava.postponeComputation(100, object : Runnable {
override fun run() {
L.d("run")
}
})
}
//전역변수인 runnable 변수는 하나만 생성되고 모든 호출에 같은 전역변수 runnable을 사용한다
for (i in 1..3) {
ramdaJava.postponeComputation(100, runnable)
}
//변수를 포획한다면 호출마다 새로 생성된다
for (i in 1..3) {
ramdaJava.postponeComputation(100) {
L.d("$i") //포획
}}
}
val ramdaJava = RamdaJava()
//프로그램 전체에서 Runnable의 인스턴스는 단 하나만 생성
for (i in 1..3) {
ramdaJava.postponeComputation(100) {
L.d("run") //인자 포획 없음
}
}
//메소드를 호출할때마다 object 가 새로 생성된다
for (i in 1..3) {
ramdaJava.postponeComputation(100, object : Runnable {
override fun run() {
L.d("run")
}
})
}
//전역변수인 runnable 변수는 하나만 생성되고 모든 호출에 같은 전역변수 runnable을 사용한다
for (i in 1..3) {
ramdaJava.postponeComputation(100, runnable)
}
//변수를 포획한다면 호출마다 새로 생성된다
for (i in 1..3) {
ramdaJava.postponeComputation(100) {
L.d("$i") //포획
}}
}
람다와 리스너 등록과 해제하기
람다는 코드 블록이기 때문에 this 는 람다를 둘러싼 클래스를 가리킵니다.그러므로 람다 안에서 this 를 사용해서 리스너를 해제해야될 경우에는 object 무명 객체를 사용해야 됩니다.
textView.viewTreeObserver.addOnPreDrawListener(
object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
logTextView.viewTreeObserver.removeOnPreDrawListener(this)
return false
}
})
object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
logTextView.viewTreeObserver.removeOnPreDrawListener(this)
return false
}
})
*개인적으로 코틀린을 공부하면서 정리한 자료입니다. 수정 사항 및 이슈가 있는 경우 메일 부탁드립니다.
댓글
댓글 쓰기