Kotlin in Action 이어서 람다에 대해 공부했다.
람다 식(lambda expression) : 다른 함수에 넘길 수 있는 작은 코드 조각.
값처럼 여기저기 전달할 수 있는 동작의 모음.
람다식을 사용하면 함수를 선언할 필요 없이 코드 블록을 직접 함수의 인자로 전달해 코드를 간결하게 유지할 수 있다.
객체의 리스트에서 특정 요소의 최대값을 구할 때, 복잡한 for문 필요없이 아래처럼 간단하게 람다와 컬렉션의 함수를 이용해 구할 수 있다.
fun main() {
val people = listOf(Person("kim", 30), Person("Ryu", 25))
println(people.maxBy { p: Person -> p.age }) // 1번
println(people.maxBy { p -> p.age }) // 2번
println(people.maxBy { it.age }) // 3번
println(people.maxBy(Person::age)) // 4번
// 모두 Person(name=kim, age=30)로 결과는 같다.
}
{ x: Int, y: Int -> x + y }
항상 중괄호 사이에 위치하고 파라미터와 본문을 ->
화살표가 구분해준다.
컴파일러는 로컬 변수처럼 람다 파라미터의 타입도 추론할 수 있으므로 위의 예시에서 1번처럼 명시할 필요는 없다. 2번처럼 써도 된다.
파라미터의 이름을 디폴트인 it
으로 바꾸면 3번처럼 더 간단히 사용할 수 있다.
단, 람다가 중첩되는 경우 가독성 측면에서 it보단 파라미터를 명시하는 편이 낫다.
코틀린 람다가 자바에서와 다른점은 파이널 변수가 아닌 변수에 접근이 가능하다.
람다 안에서 바깥의 변수(not final)를 변경해도 된다.
이처럼 람다 안에서 사용하는 변수를 람다가 포획(capture)한 변수
라 한다.
코틀린에서는 자바8과 마찬가지로 함수를 값으로 바꿀 수 있다. 이중콜론
::
을 사용한다.
val getAge = Person::age
클래스(Person)와 멤버(age)를 ::로 구분하면 된다. 예시에서 4번과 같다.
참조 대상이 함수든 프로퍼티든 뒤에 괄호는 넣으면 안된다.
(다른 클래스의 멤버가 아닌) 최상위에 선언된 함수나 프로퍼티를 참조할 수도 있다.
이 경우 클래스 이름을 생략하고 바로 ::멤버명 으로 한다.
생성자 참조
: 클래스 생성 작업을 연기하거나 저장해둘 수 있다.
::클래스명
으로 생성자를 참조한다.
data class Person(val name: String, val age: Int)
val createPerson = ::Person
val p = createPerson("Park", 15)
클래스명::확장함수명
이 방식으로 확장함수도 참조가 가능하다. 컬렉션 활용 시 기반이 되는 함수
val list = listOf(1,2,3,4,5,6) println(list.filter { it%2==0 }) // [2, 4, 6] println(list.map { it*it }) // [1, 4, 9, 16, 25, 36] println(people.map { it.name }) // [kim, Ryu] Person -> String으로 변했으므로 map println(people.filter { it.age>=30 }.map(Person::name)) // [kim]
- filter : 주어진 술어(조건, predicate)를 만족하는 원소만 남는다.
원치 않는 원소는 제거가 가능하지만, 원소를 변환할 수는 없다.
컬렉션의 모든 원소가 어떤 조건을 만족하는지 판단하는 연산을 한다. 컬렉션에 술어 적용.
컬렉션의 모든 원소를 어떤 특성에 따라 여러 그룹으로 나누고 싶을 때 사용
val people = listOf(Person("kim", 31), Person("Ryu", 25), Person("Lee", 31), Person("Son", 21))
val group = people.groupBy { it.age }
println(group)
// 출력 : {31=[Person(name=kim, age=31), Person(name=Lee, age=31)], 25=[Person(name=Ryu, age=25)], 21=[Person(name=Son, age=21)]}
먼저 인자로 주어진 람다를 컬렉션의 모든 객체에 적용하고, 결과로 얻어지는 여러 리스트를 한데 모은다.
class Book(val title: String, val authors: List<String>)
books.flatMap{ it.authors }.toSet() // 모든 저자의 집합