반응형
람다 (Λ λ)
- 11번째 그리스 알파벳 으로 대문자는 Λ, 소문자는 λ이다. 람다라고 읽으며 영어로는 lambda라고 적는다.
- 프로그래밍 언어 에서 사용되는 개념으로, 익명 함수 Anonymous functions 를 지칭하는 용어이다.
고차 함수
장점
- 코드의 간결성 : 불필요한 루프문의 삭제가 가능하며, 동일한 함수를 재활용할 수 있는 여지가 커진다.
- 인터페이스 없이 콜백구조를 간단하게 구현할 수 있다.
- 지연 연산을 지원하는 방식 을 통하여 효율적인 퍼포먼스를 기대 → 5.3절
5.1.1) 람다 소개
// Java
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view)
{
textView.setTextColor(Color.BLUE);
}
});
// Kotlin
binding.btnShare.setOnClickListener {
imageViewerAdapter.shareImage()
}
// 람다를 메서드가 하나뿐인 무명 객체를 대신해서 사용할 수 있음.
5.1.2) 람다와 컬렉션
- 코드에서 중복을 제거하는 것은 프로그래밍 스타일을 개선하는 중요한 방법
- 우리는 많은 컬렉션을 다루고, 그 방식은 대부분 일정한 패턴을 가진다.
- 람다를 지원하지 않았던 자바에서는 그러한 라이브러리가 많지 않았음.
- 대부분의 그런 작업들은 코틀린 라이브러리 함수를 통해 개선할 수 있음
5.1.3) 람다 식의 문법
{ x: Int, y: Int → x + y }
- 파라미터와 본문으로 구성됨
- 인자에 괄호가 없으며, 화살표로 인자와 본문을 구분
- 람다 전체는 항상 중괄호 사이에 위치함
val sum = { x: Int, y: Int → x + y }
println(sum(1,2))
- 변수에 람다를 저장하고 호출할수 있음
val people = listOf(Person("상윤", 35), Person("종훈", 36), Person("혜지", 30))
1) println(people.maxBy({p:Persion -> p.age}) // 맨뒤 인자가 람다면 람다를 괄호밖 가능
2) println(people.maxBy() { p:Persion -> p.age }) // 어떤함수의 유일한 인자, 괄호밖이면
3) println(people.maxBy{ p:Persion -> p.age })// 이렇게 () 를 생략 가능함.
4) println(people.maxBy{ p -> p.age }) // 컴파일러가 타입추론이 가능하므로 타입 생략가능
5) println(people.maxBy{ it.age }) // it 자동 생성된 파라미터 이름
---------------------------------------------
*Persion(name=종훈, age=36)*
---------------------------------------------
/**
* Returns the first element yielding the largest value of the given function.
*
* @throws NoSuchElementException if the collection is empty.
*
* @sample samples.collections.Collections.Aggregates.maxBy
*/
@SinceKotlin("1.7")
@kotlin.jvm.JvmName("maxByOrThrow")
@Suppress("CONFLICTING_OVERLOADS")
public inline fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T {
val iterator = this.iterator()
if (!iterator.hasNext()) throw NoSuchElementException()
var maxElem = iterator.next()
if (!iterator.hasNext()) return maxElem
var maxValue = selector(maxElem)
do {
val e = iterator.next()
val v = selector(e)
if (maxValue < v) {
maxElem = e
maxValue = v
}
} while (iterator.hasNext())
return maxElem
}
---------------------------------------------
/**
* A generic ordered collection of elements. Methods in this interface support only read-only access to the list;
* read/write access is supported through the [MutableList] interface.
* @param E the type of elements contained in the list. The list is covariant in its element type.
*/
public interface List<out E> : Collection<E> {
---------------------------------------------
/**
* A generic collection of elements. Methods in this interface support only read-only access to the collection;
* read/write access is supported through the [MutableCollection] interface.
* @param E the type of elements contained in the collection. The collection is covariant in its element type.
*/
public interface Collection<out E> : Iterable<E> {
---------------------------------------------
public class Int private constructor() : Number(), Comparable<Int> {
5.1.4) 현재 영역에 있는 변수에 접근
- 자바에서는 무명내부 클래스 정의할때 메소드 로컬변수를 무명 내부클래스에서 사용할수 있다.
- 파이널로 된 경우만 가능한데, 왜 이렇게 만들었을까?
public void insert(final Bbs bbs) {
getJdbcTemplate().update(sql, new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
// TODO Auto-generated method stub
ps.setString(1, bbs.getSeq());
ps.setString(2, bbs.getTitle());
ps.setString(3, bbs.getWriter());
ps.setString(4, bbs.getContent());
}
});
}
// 참고
지역변수를 final로 지정하면 JVM constant pool에서 따로 변수를 관리
- 코틀린은 208P / 209P 참고
5.1.5) 멤버참조
- Person::age
- 클래스::멤버
- 멤버 → 프로퍼티 또는 메서드
people.maxBy(Person::age)
people.maxBy{p→p.age}
people.maxBy{it.age}
5.2 컬렉션 함수형 API
- 함수형의 장점 중 하나가 컬렉션을 다루기 편의하다는 것
- 데이터를 표현하기 위해 컬렉션을 많이 다뤄야하고, 사실 이것들은 일정한 패턴이 있음
- 따라서 라이브러리를 사용하면 간결하게 만들수 있음
- 람다는 이것들을 매우 적극적으로 쓸수 있게 해준다.
→잘 알아두면 코테를 잘 볼 수 있따.
5.2.1 filter & map
Filter
val people = listOf(person("상윤", 35), Persion("종훈", 36), Persion("혜지", 30))
println(people.filter{it.age>30})
/**
* Returns a list containing only elements matching the given[predicate].
*
*@samplesamples.collections.Collections.Filtering.filter
*/
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
return filterTo(ArrayList<T>(), predicate)
}
/**
* Appends all elements matching the given [predicate] to the given [destination].
*
* @sample samples.collections.Collections.Filtering.filterTo
*/
public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(destination: C, predicate: (T) -> Boolean): C {
for (element in this) if (predicate(element)) destination.add(element)
return destination
}
Map
val people = listOf(person("상윤", 35), Persion("종훈", 36), Persion("혜지", 31))
println(people.map{it.age + 1})
/**
* Returns a list containing the results of applying the given [transform] function
* to each element in the original collection.
*
* @sample samples.collections.Collections.Transformations.map
*/
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
/**
* Applies the given [transform] function to each element of the original collection
* and appends the results to the given [destination].
*/
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
for (item in this)
destination.add(transform(item))
return destination
}
- 결과적으로 보면, 이런것들을 쓰지 않았을때랑 코드가 거의 같다는 것을 알수 있음
- 하지만 이런 패턴을 공용화 했다는 것 → 결국 가독성과 효율성을 높이는 방법이 되었음.
잘못쓰는 경우
people.filter { it.age == people.maxBy(Persion::age)!!.age }
**N명이라고 했을때 시간복잡도는? N^2**
/**
* Returns the first element yielding the largest value of the given function or `null` if there are no elements.
*
* @sample samples.collections.Collections.Aggregates.maxByOrNull
*/
@SinceKotlin("1.4")
public inline fun <T, R : Comparable<R>> Iterable<T>.maxByOrNull(selector: (T) -> R): T? {
val iterator = iterator()
if (!iterator.hasNext()) return null
var maxElem = iterator.next()
if (!iterator.hasNext()) return maxElem
var maxValue = selector(maxElem)
do {
val e = iterator.next()
val v = selector(e)
if (maxValue < v) {
maxElem = e
maxValue = v
}
} while (iterator.hasNext())
return maxElem
}
val maxAge = people.maxBy(Persion::age)!!.age
people.filter { it.age == maxAge }
**N명이라고 했을때 시간복잡도는? N+N = 2N**
5.2.2 all, any, count, find = firstOrNull
책 참조 (217)
5.2.3 Group By
data class Person(val name: String, val age: Int)
val students = listOf(
Person("종훈", 21),
Person("상윤", 21),
Person("혜지", 20),
Person("정웅", 20),
)
println(students.groupBy { it.age })
// Map<Int, List<Person>>
5.2.4 Flatmap & Flatten
val numbers = listOf(listOf(1,2,3), listOf(5,6,7), listOf(8,9,0))
val result = numbers.flatten()
println(result)
[1, 2, 3, 5, 6, 7, 8, 9, 0]
val numbers = listOf(listOf(1,2,3), listOf(5,6,7), listOf(8,9,0))
val result = numbers.flatMap { it.map { "num $it"} }
println(result)
[num 1, num 2, num 3, num 5, num 6, num 7, num 8, num 9, num 0]
반응형
'코틀린 & Java > 코틀린인액션' 카테고리의 다른 글
Kotlin Plus 산술연산자 오버로딩 (0) | 2023.05.09 |
---|---|
코틀린 원시타입(Kotlin Primitive Type) (0) | 2023.04.06 |
코틀린 타입 종류 Null가능성 (0) | 2023.03.27 |
[Kotlin] 스코프 펑션(Scoepe Function) (0) | 2023.03.23 |
[Kotlin] 람다에 대해 알아보자(2) (0) | 2023.03.23 |