Backend
home

10. 람다식

생성일
2025/02/06 13:36
태그
Kotlin

람다란 무엇인가?

람다란 일종의 익명 함수이며, 로직이다. 함수에 로직을 넘기기 쉽게 하기 위해 활용
/* 람다가 없던 구형 자바 */ button.setOnClickListener(new OnClickListener() { @override public void onClick(View view) /* 클릭 시 수행할 동작 */ } }); /* 자바의 람다식 */ button.setOnClickListener(/* (인자)-> 실행 문장 */)
Java
복사
setOnClickListener에 클릭 시 수행할 동작 하나를 전달하기 위해 특정 인터페이스를 구현하는 익명 클래스를 만들어야 하기 때문에 매우 복잡함
Java8 부터는 자바에서도 람다식을 도입함 → 코틀린은 해당 수식을 더 간결하게 해줌
코틀린의 람다식
button.setOnClickListener { /* 클릭 시 수행할 동작 */ }
Kotlin
복사
매우 간결해짐
함수 호출을 ()가 아닌 {}로 함
람다식의 장점
val persons = listOf( Person("Captain", 44), Person("Cyclops", 35), Person("Deadpool", 31), Person("Iceman", 54), ) fun main() { // 가장 나이가 많은 사람을 출력 println(persons.maxByOrNull { it.age }) } == 결과 == Person(name=Iceman, age=54)
Kotlin
복사
매우 높은 간결성과 한눈에 보이는 가독성

람다식의 문법

fun sum(x: Int, y: Int): Int = x + y
Kotlin
복사
위의 함수를 람다식으로 변경하면
람다를 사용하는 방법
함수에 파라미터 람다식 넘기기
람다식을 변수에 저장하고 해당 식을 나중에 필요할 때 실행시키기
fun sum(x: Int, y: Int): Int = x + y val sumLambda = { x: Int, y: Int -> x + y } fun main() { // 일반 함수 호출 println(sum(12, 34)) // 람다 변수 호출 println(sumLambda(12, 34)) // 람다 수식 바로 실행 println({ x: Int, y: Int -> x + y }(12, 34)) }
Kotlin
복사
람다 수식의 다양성, 간결화 수행
// 가장 정석적인 람다 호출, 람다 수식(중괄호)를 함수 호출에 인자로 넣어줌 println(persons.maxByOrNull({ person: Person -> person.age })) // 가장 마지막 인자가 람다식이면 함수 호출 밖으로 뺄 수 있음 println(persons.maxByOrNull() { person: Person -> person.age }) // 람다만 있는 경우 빈괄호 삭제 가능 println(persons.maxByOrNull { person: Person -> person.age }) // 컴파일러가 타입 추론 println(persons.maxByOrNull { person -> person.age }) // 람다의 파라미터 이름을 기본 이름인 it으로 수정하면 가장 간결한 람다식이 완성 println(persons.maxByOrNull { it.age })
Kotlin
복사
단일 파라미터만 사용하는 람다식에서 주로 최종 단계 수준으로 활용
다중 파라미터이거나 컴파일러 타입 추론이 어려운 경우 그리고 깊이가 있는 수식인 경우엔 it이나 타입 추론을 사용하기 어려울 수 있음
멤버(함수) 참조
println(persons.maxByOrNull { person -> person.age }) // 이미 정의된 동일한 함수가 있으므로 해당 함수를 넘긴다 println(persons.maxByOrNull(Person::age))
Kotlin
복사
이중 콜론(::)을 활용해서 특정 클래스의 프로퍼티나 메서드를 참조할 수 있음
최상위 함수나 값의 경우 ::topLevelFunction 처럼 클래스명 지정 없이 바로 참조함

컬렉션 함수형 API

filter, map
가장 기초가 되는 함수
filter : 데이터를 필터링
map : 데이터를 다른 데이터로 변환(매핑)
다른 복잡한 함수들도 이것들을 활용하여 만들 수 있음
val persons = listOf( Person("Captain", 44), Person("Cyclops", 35), Person("Deadpool", 31), Person("Iceman", 54), ) fun main() { println(persons.filter { it.age > 36 }) println(persons.filter { it.age > 36 } .map { "${it.name}'s age is ${it.age}" }) } == 결과 == [Person(name=Captain, age=44), Person(name=Iceman, age=54)] [Captain's age is 44, Iceman's age is 54]
Kotlin
복사
persons에서 나이가 36세 초과인 사람만 filtering
필터링 후 해당 결과를 String으로 maping(변환)
all, any, count, find
all : 모두 조건에 맞는가?
any : 하나라도 조건에 맞는가?
count : 조건에 맞는 원소의 개수를 구함
find : 조건에 맞는 원소를 하나만 주거나, 없으면 null을 응답
groupBy
특정 값으로 key를 만들고 해당 값에 해당하는 원소를 리스트로 갖는 map 객체를 만듦
val persons = listOf( Person("Captain", 44), Person("Cyclops", 35), Person("Deadpool", 31), Person("Iron Man", 31), Person("Iceman", 54), Person("Loki", 54), Person("Hulk", 54), ) fun main() { println(persons.groupBy { it.age }) } ==== 결과 ==== { 44=[Person(name=Captain, age=44)], 35=[Person(name=Cyclops, age=35)], 31=[Person(name=Deadpool, age=31), Person(name=Iron Man, age=31)], 54=[Person(name=Iceman, age=54), Person(name=Loki, age=54), Person(name=Hulk, age=54)] }
Kotlin
복사
flatMap, flatten
flatten : 중첩 컬렉션(List<List<T>>와 같은)를 단일 컬렉션(List<T>)로 만들어줌
flatMap
map + flatten
map 이후에 중첩 컬렉션이 발생되는 경우 flatMap을 활용하면 단일 컬렉션으로 결과를 바로 만들어줘서 편함
col.map.flatten() → col.flatMap
하지만 이런 용도로 실제 활용할 일은 잘 없고, 함수형 프로그래밍에서 매우 적극적으로 활용하게 됨
fun main() { val strings = listOf("abc", "def") println(strings.map { it.toList() }) println(strings.map { it.toList() }.flatten()) println(strings.flatMap { it.toList() }) } ==== 결과 ==== [[a, b, c], [d, e, f]] [a, b, c, d, e, f] [a, b, c, d, e, f]
Kotlin
복사
sequence
자바의 스트림과 같은 역할을 함
대량 컬렉션에 필터링이나 찾기 연산을 하는 경우 유용함
sequence가 아닌 경우 무조건 모든 결과를 계산
sequence는 조건에 맞는 경우, 결과가 필요한 경우에 한해서 계산을 진행
val persons = listOf( Person("Captain", 44), Person("Cyclops", 35), Person("Deadpool", 31), Person("Iceman", 54), Person("Loki", 54), Person("Hulk", 54), ) fun main() { println( persons.map { println(it) it.name }.find { it.startsWith("I") } ) println( persons.asSequence() .map { println(it) it.name }.find { it.startsWith("I") ) } ==== 결과 ==== Person(name=Captain, age=44) Person(name=Cyclops, age=35) Person(name=Deadpool, age=31) Person(name=Iceman, age=54) Person(name=Loki, age=54) Person(name=Hulk, age=54) Iceman Person(name=Captain, age=44) Person(name=Cyclops, age=35) Person(name=Deadpool, age=31) Person(name=Iceman, age=54) Iceman
Kotlin
복사
일반 컬렉션 : 모두 map을 진행한 후 find를 수행
sequence
개별 원소마다 map과 find를 진행
find에서 조건이 맞는 원소를 찾는 즉시 더 이상의 연산 수행하지 않음
대량의 원소에서 필터링이나 find를 수행할 때 활용하면 좋을 수 있음