목록전체 글 (254)
시스템아 미안해
불변 컬렉션(immutable collection) 대신 가변 컬렉션(mutable collection) 을 사용하는 가장 큰 장점은 성능이 더 빠르다는 점입니다. 불변 컬렉션에 요소를 추가할 때는 새로운 컬렉션을 생성한 뒤,기존 요소들을 모두 복사하고 새로운 요소를 추가해야 합니다. 다음은 Kotlin 표준 라이브러리(Kotlin 1.2)에서 이러한 방식이 어떻게 구현되어 있는지를 보여주는 예시입니다.operator fun Iterable.plus(element: T): List { if (this is Collection) return this.plus(element) val result = ArrayList() result.addAll(this) result.add(eleme..
Kotlin에서는 직접적으로 원시 타입(primitive)을 선언할 수는 없지만,내부적으로는 성능 최적화를 위해 원시 타입이 사용됩니다. 이는 앞서 Item 47: Avoid unnecessary object creation에서 설명했듯이,상당히 중요한 최적화 방식입니다. 원시 타입은 다음과 같은 장점이 있습니다.더 가볍습니다. 객체는 추가적인 메모리를 차지하기 때문입니다.더 빠릅니다. 접근자(accessor)를 통한 값 접근이나 객체 생성 자체가 추가 비용이기 때문입니다.따라서 대량의 데이터를 다룰 때 원시 타입을 사용하는 것은 매우 중요한 최적화가 될 수 있습니다. 하지만 한 가지 문제가 있습니다.Kotlin의 일반적인 컬렉션(List, Set 등)은 제네릭(generic) 이기 때문에,원시 타입을 ..
모든 컬렉션 처리 메서드는 비용(cost) 을 수반합니다. 표준 컬렉션 처리의 경우 비용은 다음과 같습니다.요소들을 추가로 한 번 더 순회(iteration) 해야 합니다.내부적으로 새로운 컬렉션이 생성됩니다.반면 Sequence 처리의 경우 비용은 다음과 같습니다.전체 시퀀스를 감싸는 추가 객체가 생성됩니다.람다 표현식이 생성됩니다.이러한 비용들은 일반적으로는 작지만,요소의 개수에 비례하여 증가하기 때문에,컬렉션이 커질수록 무시하기 어려운 수준이 될 수 있습니다. 이 비용을 줄이는 가장 기본적인 방법 중 하나는여러 연산을 하나로 합친(composite) 함수를 사용하는 것입니다. 예를 들어:null이 아닌 값을 필터링한 뒤 non-null 타입으로 캐스팅하는 대신 → filterNotNull을 사용ma..
제가 컬렉션 처리 관련 도움을 드릴 때 자주 느끼는 점은,많은 분들이 요소들을 그룹화할 수 있다는 사실을 간과하고 있다는 것입니다. 다음과 같은 작업들은 모두 그룹화(grouping) 가 필요한 대표적인 예입니다.사용자 목록을 기반으로 도시별 사용자 수를 계산하는 작업선수 목록을 기반으로 팀별 획득 점수를 계산하는 작업옵션 목록을 기반으로 각 카테고리별 최적의 선택을 찾는 작업Iterable에서 요소를 그룹화하는 방법에는 두 가지가 있습니다.첫 번째 방법은 더 간단하지만,두 번째 방법은 더 빠르게 동작합니다. 이제 이 두 가지 방법을 각각 살펴보겠습니다.groupBy이 문제를 해결하는 가장 쉬운 방법은 groupBy 함수를 사용하는 것입니다. 이 함수는 Map 형태의 결과를 반환합니다.여기서V는 원래 컬..
큰 규모의 데이터 집합에서 키(key)를 기준으로 특정 요소를 찾아야 하는 상황은 흔하게 발생합니다. 이러한 경우는 다음과 같은 상황일 수 있습니다.하나 이상의 파일에서 로드된 설정(configuration)을 저장하는 클래스다운로드된 데이터를 저장하는 네트워크 저장소(repository)테스트에서 자주 사용되는 메모리 기반 저장소(in-memory repository)이 데이터는 사용자 목록, ID 목록, 설정 값 등 다양한 형태일 수 있습니다. 일반적으로 이러한 데이터는 리스트(List) 형태로 가져오기 때문에,메모리에서도 동일하게 리스트로 표현하고 싶은 유혹이 생기기 쉽습니다.class ConfigurationRepository( private val configurations: List) {..
Iterable과 Sequence의 차이를 놓치는 경우가 많습니다. 정의만 보면 거의 동일하기 때문입니다:interface Iterable { operator fun iterator(): Iterator}interface Sequence { operator fun iterator(): Iterator}이 둘의 형식적인 차이는 이름뿐이라고 볼 수도 있습니다.하지만 Iterable과 Sequence는 완전히 다른 사용 방식(서로 다른 계약, contract) 을 가지고 있기 때문에,대부분의 처리 함수들도 서로 다르게 동작합니다. Sequence는 지연(lazy) 처리 방식을 사용합니다.따라서 Sequence를 처리하는 중간 연산(intermediate function)들은 실제 계산을 수행하지 않..