람다? 람다 식(lambda expression)?
다른 함수에 넘길 수 있는 작은 코드 조각
→코드 블록을 함수 인자로 넘기기
값처럼 여기저기 전달할 수 있는 동작의 모음
→함수형 언어에서 함수를 직접 다른 함수에 전달하기.
+추가
익명클래스로 선언된 구현부를 변수처럼 쓸수 있게 해준다.
(변수처럼? 여기저기 넣을수있음)
람다 식을 사용하면 코드가 더 간결해짐.
→함수를 선언할 필요가 없고 코드 블록을 직접 함수의 인자로 전달할 수 있다.
예제
-버튼 클릭에 따른 동작 정의하는 경우 클릭 이벤트를 처리하는 리스너를 추가한다.
button.setOnClickListener(new OnClickListener() {
@Override public void onClick(View view) {
/* 클릭 시 수행할 동작 */
}
}//무명 내부 클래스 선언하느라 번잡한 코드
button.setOnClickListener {
/* 클릭 시 수행할 동작 */
}// 람다로 리스너 구현
→람다를 메소드가 하나뿐인 무명 객체 대신 사용할 수 있다.
멤버 참조를 인자로 취하는 것
멤버 참조?
::를 사용하는 식을 멤버 참조라고 한다.
클래스::멤버
(메소드, 생성자, 프로퍼티의 이름 앞에 ::을 붙이면 각각에 대한 참조를 만들 수 있다.)
people.maxBy(Person::age)
: 프로퍼티나 메소드를 단 하나만 호출하는 함수 값을 만들어준다.
→함수를 직접 넘겨 주기
그런 참조를 람다 대신 다른 함수에게 넘길 수 있다.
함수의 인자를 람다나 멤버 참조로 받게 만든 코드는 더 짧고 더 이해하기 쉽다
람다 식 문법
{ x: Int, y: Int → x+y }
코틀린 람다 식은 항상 중괄호로 둘러싸여 있다
→ 화살표가 인자 목록과 람다 본문을 구분해준다.
람다 식을 변수에 저장하기
val sum = { x: Int, y: Int → x+y }
println( sum(1, 2) ) // 변수에 저장된 람다를 호출한다.
코틀린에는 함수 호출 시 맨 뒤에 있는 인자가 람다 식이라면
그 람다를 괄호 밖으로 빼낼 수 있다는 문법 관습이 있다.
people.maxBy() { p: Person → p.age }
람다가 어떤 함수의 유일한 인자이고,
괄호 뒤에 람다를 썼다면 호출 시 빈 괄호를 없애도 된다.
people.macBy {p: Person → p.age }
람다가 함수의 유일한 인자라면 괄호 없이 람다를 바로 쓰기를 원하게 된다.
컴파일러는 람다 파라미터의 타입도 추론할 수 있다.
people.maxBy { p: Person → p.age }
people.maxBy { p → p.age } // 타입 추론이 가능해서 : Person 생략!
디폴트 파라미터 이름 it 사용하기
people.maxBy { it.age }
람다에서 변수 포획하기.
변수를 포획한다? 포획한 변수?
→람다 안에서 사용하는 외부 변수를 람다가 포획한 변수라고 부른다.
코틀린에서는 람다에서 람다 밖 함수에 있는 변수에 접근할 수 있고, 그 변수를 변경할 수도 있다.
자바에서는 파이널 변수만 포획할 수 있다.
자바에서 변경 가능한 변수를 포획하는 방법(속임수)은
변경 가능한 변수를 저장하는 원소가 단 하나뿐인 배열을 선언하거나,
변경 가능한 변수를 필드로 하는 클래스를 선언.
→"변경 가능한 변수를 필드로 하는 클래스를 선언" → 이렇게 코틀린이 컴파일 된다.
var counter = 0 val inc = { counter++ } // 코틀린으로 이렇게 작성하면?
class Ref<T>(var value: T) // 이렇게 컴파일 된다.
val counter = Ref(0)
val inc = { counter.value++ }
시퀀스 인터페이스
(컬렉션 연산을 연쇄 실행하는)연쇄 호출에서 리스트를 2개 만든다면 시퀀스를 사용하면 효율적이다.
시퀀스 안에는 iterator 라는 단 하나의 메소드가 있다.
그 메소드를 통해 시퀀스로부터 원소 값을 얻을 수 있다.
시퀀스의 원소는 필요할 때 계산된다.
→시퀀스에 대한 연산을 지연 계산하기 때문에 정말 계산을 실행하게 하려면 최종 시퀀스의 원소를
하나씩 이터레이션하거나 최종 시퀀스를 리스트로 변환해야한다.
OnClickListener에 추상 메소드가 단 하나만 있기 때문이다 (onClick)
그런 인터페이스를 함수형 인터페이스 또는 SAM 인터페이스라고 한다.
SAM은 단일 추상 메소드 Single Abstract Method 라는 뜻이다.
코틀린은 함수형 인터페이스를 인자로 취하는 자바 메소드를 호출할 때 람다를 넘길 수 있게 해준다.
수신 객체 지정 람다
자신에게 전달된 객체 →수신 객체
with(수신객체) {람다 식}
: 인자를 두개 받는데
첫번째 파라미터 → 수신객체
두번째 파라미터 → 람다 식으로 받는것임.
with() 가 반환하는 값
→수신객체를 인자로 받아서 람다 코드를 실행한 결과. 마지막 메소드를 결과 값으로 반환.
→it 주의
수신객체.apply() {람다 식}
apply() 가 반환하는 값
→수신객체를 반환함. 확장함수로 정의되어 있다.
→ 프로퍼티 초기화할 때 많이 사용하는 함수.
fun tryToCountButtonClicks (button: Button) : Int {
var clicks = 0
button.onClick { clicks++ }
// button.setOnClickListener(new onClick() { clicks++ } );
return clicks
}
비동기
→ 이 함수는 항상 0을 반환한다.
onClick 핸들러는 호출될 때마다 clicks의 값을 증가시키지만 그 값의 변경을 관찰할 수는 없다.
관찰?
onClick은 tryToCountButtonClicks가 clicks를 반환한 다음에 호출되기 때문이다.
tryToCountButtonClicks는 호출하면 바로 clicks를 return하고
onClick은 click을 기다렸다가 클릭 되면 그때서야 나~중에 clicks++ 되기 때문이다.
'Kotlin' 카테고리의 다른 글
Kotlin in action 7장 연산자 오버로딩과 기타 관례 (0) | 2020.04.23 |
---|---|
Kotlin in action 6장 코틀린 타입 시스템 (0) | 2020.04.13 |