코틀린/Kotlin Lang

[Kotlin] 코틀린 Collection과 불변성

sxunea 2024. 3. 4. 22:39

 

 


컬렉션은 수집이라는 단어 의미 그대로 다수의 객체를 수집해놓은 객체를 의미한다. 자바에도 컬렉션이 존재하지만, 코틀린은 그 특성 처럼 read - only, mutable interface 모두 제공한다.

 

코틀린 컬렉션 인터페이스의 다이어그램

Note that a mutable collection doesn't have to be assigned to a var. Write operations with a mutable collection are still possible even if it is assigned to a val. The benefit of assigning mutable collections to val is that you protect the reference to the mutable collection from modification.

 

 

List

- 내부 요소들을 정해진 순서로 저장하고, indexed access를 제공

- 중복된 요소가 들어갈 수 있다

// immutable List
val numbers = listOf("one", "two", "three", "four") 

// mutable List
val numbers = mutableListOf(1, 2, 3, 4)
	numbers.add(5)
	numbers.removeAt(1)
    
val numbersList = mutableListOf<Int>()

 

 

Set

- 중복된 요소가 들어갈 수 없고, 순서 또한 유지 되지 않는다

- 하나의 null만 저장 가능하다 

- LinkedHashSet, HashSet, TreeSet

 

// immutable
var numberSet = setOf<Int>(1,2,3,3,3)

// mutable
val mNumberSet = mutableSetOf<Int>(1,2,3,4,4,4)
mNumberSet.add(5) 
println(mNumberSet) // 1,2,3,4,5 출력

 

 

Map

- Map은 사실 컬렉션 인터페이스를 상속받지는 않지만, 코틀린 컬렉션 타입이긴 하다

- key - value를 쌍으로 가지고, key는 unique하게 가진다

 

// immutable
var imnumberMap = mapOf<String,Int>("one" to 1,"two" to 2)
  
// mutable
val mNumberMap = mutableMapOf<String,Int>("one" to 1,"two" to 2)
mNumberMap.put("three",3) 
println(mNumberMap) // {one=1, two=2, three=3} 출력

 

자바와 코틀린의 불변 컬렉션

 

자바에서 불변 컬렉션을 생성하는 방법으로는 unmodifiableList(), unmodifiableSet(), unmodifiableMap() 을 통해, 가변 기존 컬렉션의 요소가 복사된 불변 컬렉션을 생성할 수 있다.

 

코틀린에서는 컬렉션 인터페이스 자체가 불변인 Collection과 가변인 MutableCollection로 나뉘어져있다. MutableCollection의 내부를 살펴보면, 기본적으로 가변 Map, Set, List에 제공하는 다음과 같은 함수들이 들어있다.

 

 

  • add()
  • remove()
  • addAll()
  • removeAll()
  • retainAll()
  • clear()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

코틀린의 가변성 제한을 위한 컬렉션 계층 설계

앞서 말했듯이 코틀린은 읽고 쓸 수 있는 컬렉션과 읽기 전용 컬렉션으로 구분된다.

이때, mutable 컬렉션이 내부의 값을 변경할 수 없다는 의미는 아니다. 컬렉션의 내용을 변경하는 메소드를 호출할 수 없을 뿐, 실제로는 컬렉션의 내용이 변경될 수 있다는 거다. 

 

val mutableIntList = mutableListOf(1, 2, 3, 4)
val readOnlyIntList : List<Int> = mutableIntList

 

다음과 같이 두 리스트가 있다고 하면, readOnlyIntList는 mutableIntList의 읽기 전용 컬렉션이기 때문에 내용을 변경하는 add(), remove() 같은 함수를 호출 할 수 없다. 하지만 mutableIntList에서는 가능하고, 그 변경은 readOnlyIntList에도 반영된다. 

 

이처럼 읽기 전용 컬렉션은 내부적으로는 변경 가능하지만 외부적으로는 불변으로 보이게 만드는 안정성을 제공한다. 이는 컬렉션을 안전하게 공유하면서도 필요에 따라 내부에서 변경할 수 있는 유연성을 제공한다. 내부적으로는 인터페이스를 사용하고 있으므로, 실제 컬렉션을 리턴할 수 있어 플랫폼 고유의 컬렉션을 사용할 수 있다.

 

불변 객체는 다음과 같은 장점을 가진다.

 

  • 한번 정의된 상태가 유지되므로 코드 이해가 쉽다
  • 공유했을때도 충돌이 없으므로 병렬 처리가 안전하고, 객체의 참조 또한 변경되지 않아 캐시가 쉽다
  • 객체를 복사할 때 깊은 복사를 따로 해줄 필요가 없다
  • 상태 변경이 없으므로 디버그, 상태 처리, 동기화, 테스트 모두가 용이하다

따라서 특정한 상황이 아니고서는 immutable 객체를 사용하는 것이 좋으며, 변경이 필요하다면 immutable을 copy해 활용하는 것이 좋다. 이렇게 코틀린의 컬렉션과 불변성이라는 특징을 알아보았고, 다음에는 컬렉션에서 제공하는 연산 및 함수들에 대해 알아봐야겠다 

 

 

 

참고자료 

 

 

Collections overview | Kotlin

 

kotlinlang.org