사진: Unsplash의Tahlia Doyle
List에 대해서 배울 때, 우리는 일반적으로 MutableList와 비교하며 List는 변경될 수 없는 Immutable한 컬렉션이라고 배웠습니다.
다만, 이는 큰 관점에서는 틀린 정보입니다. 그래서 이번 게시글에서는 List가 왜 Immutable하지 않는지, 그리고 Immutable한 컬렉션은 뭐가 있는지 알아보고자 합니다.
List는 Immutable하지 않다!
List는 Read-only라고 말합니다. 변경할 수 없고, 오직 읽을 수만 있는 컬렉션이라고 우리는 배워왔습니다.
다만, 이는 넓은 관점에서는 틀린 말입니다.
아래의 코드를 보겠습니다. 변수 `number`는 val로 선언되어 있기 때문에 변경될 수 없습니다.
class Example {
val number = 12
}
코틀린에서 이러한 변수들은 프로퍼티라고 부릅니다. 코틀린에서는 자바의 필드를 코드 내부에 캡슐화하여 프로퍼티를 통한 간접적인 접근을 가능하게 합니다.
public final class Example {
private final int number = 12;
public final int getNumber() {
return this.number;
}
}
자바의 관점에서 필드가 final로 선언되었다면, 이는 어떠한 상황에서 변하지 않는 값이 됩니다.
이제 리스트를 한번 보겠습니다. 아래의 예시에서는 이전의 number를 리스트 안에 담고, 이를 val로 선언하여 불변으로 만들었습니다.
class Example {
val number = 12
}
fun main() {
val list = Arrays.asList(Example().number)
}
자바에서 Arrays.asList는 기본적으로 가변적입니다. 따라서, number의 값이 변경될 수는 없지만 리스트가 참조하고 있는 값은 언제든지 재할당될 수 있습니다.
public static final void main() {
List list = Arrays.asList((new Example()).getNumber());
}
이를 좀 더 쉽게 설명하기 위해 간단한 예시를 들어보겠습니다.
여기 가변으로 선언된 리스트와 불변으로 선언된 리스트가 있습니다.
fun main() {
val mutableList = mutableListOf(1, 2)
val list: List<Int> = mutableList
}
여기서 만약 가변 리스트를 변경시킨다면 어떻게 될까요??? 가변 리스트의 값만 바뀌고 이를 참조하고 있는 불변 리스트의 값은 바뀌지 않을까요???
정답은 불변 리스트의 값 또한 바뀐다는 것입니다.
fun main() {
val mutableList = mutableListOf(1, 2)
val list: List<Int> = mutableList
mutableList.add(3)
println(list) // [1, 2, 3]
}
하나의 예시를 더 들어보겠습니다. 불변 리스트를 정의한 다음, 다른 변수에 불변 리스트를 캐스하고, 가변 리스트로 할당해 보겠습니다.
이러한 경우에도 기존 불변 리스트의 값은 변하게 됩니다.
fun main() {
val list: List<Int> = listOf(1, 2)
val mutableList = list as MutableList<Int>
mutableList[0] = 100
println(list) // [100, 2]
}
Immutable한 컬렉션을 만드는 방법
어떠한 상황에서 변하지 않는 Immutable한 컬렉션을 만드는 방법은 다양합니다. 다만 여기서는 Kotlin에서 Immutable 컬렉션을 만들 수 있는 방법인 Immutable Collection과 추가로 Persistent Collection을 지원하는 라이브러리에 대해 알아보고자 합니다.
Immutable Collection은 간단합니다. 확장 함수로 Immutable로 변경해주기만 하면 해당 컬렉션은 이제 어떠한 방식으로도 변경할 수 없는 컬렉션이 됩니다.
fun main() {
val mutableList = mutableListOf(1, 2)
val list: List<Int> = mutableList.toImmutableList()
mutableList.add(3)
println(list) // [1, 2]
}
Persistent Collection은 기본 데이터 구조의 포인터를 업데이트 해서 컬렉션의 변경 사항을 반영하는 방식으로만 수정할 수 있는 컬렉션입니다.
Immutable Collection을 기반으로 하여 수정 작업이 가능하게 만든 컬렉션이라 생각하면 될 것 같습니다.
Persistent Collection은 변경 내용이 있을 경우, 이를 반영하는 새로운 컬렉션을 생성하는 방식으로 수정 작업을 처리합니다.
Compose에서 이러한 컬렉션을 사용해야 하는 이유
Compose의 Reposition은 컴포저블의 매개변수 상태가 변할 때 일어나게 됩니다.
만약 매개변수의 타입이 불안정하거나 변경될 수 있다면, 해당 컴포저블에 Reposition이 일어나게 됩니다.,
만약 해당 컴포저블에 Reposition을 발생시키지 않고자 하려면, 해당 매개변수를 Stable하게 유지해서 컴포저블이 Reposition되지 않게 해야할 것입니다.
그렇기 때문에 Reposition을 발생시키지 않기 위해서 우리는 매개변수가 될 수 있는 컬렉션을 Immutable Collection으로 사용하는 것이 좋습니다.
Reference
'Android > Kotlin' 카테고리의 다른 글
Kotlin에서의 함수 컬러링이란? suspend와 composable 함수 (1) | 2024.10.15 |
---|---|
KAPT, KSP 그리고 어노테이션 (3) | 2024.09.11 |
Ktor에 대해 알아보고 HTTP 통신 해보기 (1) | 2023.12.04 |
@Inject로도 @Provide할 수 있다 (0) | 2023.11.25 |
코틀린에서 Backing Properties를 왜 사용해야 하죠? (2) | 2023.11.22 |