코틀린 표준 라이브러리에는 container type인 시퀀스가 있다. 이 시퀀스는 Iterable object에 사용할 수 있다.
기존의 Iterable이 전체 collection에 대해 정의된 순서대로 확장 함수들을 완료하고 다음 단계로 넘어갔다면
시퀀스는 각각 하나의 엘리먼트가 확장함수들을 수행하고 다음 단계로 넘어간다.
물론 크기가 매우 작은 Iterable일 때는 상관없겠지만, 반대로 매우 클 경우에 발생할 수 있는 오버헤드를 해결할 수 있는 유용한 방법이다.
그러므로 상황에 따라 시퀀스를 쓸지 그냥 Iterable 그대로 쓸지 잘 생각해봐야 한다.
일반적인 Iterable이 체인되어 있는 확장 함수들에서 어떻게 동작하는지 확인해보자.
val maxEvenSquare = listOf(1, 2, 3, 4, 5) //[1, 2, 3, 4, 5]생성
.map { it * it } //[1, 4, 9, 16, 25]생성
.filter { it % 2 == 0 } //[4, 16] 생성
.maxOf { it } //[16] 생성
위 코드처럼 맨 처음 IterableList가 생성될 때, 그리고 연산들이 수행됨에 따라 불필요한 intermediate collection이 생성된다.
만약 연산이 하나뿐이라면 상관없지만 이런식으로 체인 된 처리는 오버헤드가 발생할 수밖에 없다.
이러한 문제점을 해결하기 위해 sequence를 사용해보자.
val maxEvenSquare = listOf(1, 2, 3, 4, 5) //[1, 2, 3, 4, 5]생성
.asSequence()
.map { it * it }
.filter { it % 2 == 0 }
.maxOf { it }
이렇게 list를 sequece로 만들어 처리하면 중간중간 intermediate collection을 생성하지 않고 각각의 엘리먼트를 순차적으로 계산하기 때문에 조건만 만족하다면 이터레이션을 종료할 수 있다.
sequence() 함수를 통해 임의로 설정된 엘리먼트로 시퀀스를 만들 수 있다.
바로 yield()와 yieldAll() 함수이다.
yield()는 한개의 엘리먼트를 argument로 설정할 수 있고, yieldAll()는 Iterable object나 또 다른 시퀀스를 argument로 설정할 수 있다.
이때 yieldAll()의 argument가 되는 Sequence는 항상 마지막으로 호출되어야하고, 순서에 주의하지 않으면 그 뒤에 정의된 argument들은 무시된다.
'Kotlin' 카테고리의 다른 글
[Kotlin] Delegated Properties (0) | 2022.03.23 |
---|---|
[Kotlin] Delegation (0) | 2022.03.22 |
[Kotlin] 코틀린에서 RxJava와 Coroutine (0) | 2022.01.06 |
[Kotlin] Coroutine 동기화 처리 (0) | 2021.12.21 |
[Kotlin] inline 함수 (0) | 2021.09.06 |