본문 바로가기

Kotlin/이펙티브코틀린

1장 : item 1

1장은 안정성을 주제로 10가지 아이템을 다루고 있다.

 

Item 1 : 가변성을 제한하라


가변성을 제한하는 이유 

  • 많은 부분에서 변화가 생기면 디버깅이 어려워진다
  • 테스트하기 어렵다
  • 멀티스레드 환경일 경우 동기화가 필요한데, 변경이 많을수록 충돌 지점도 많아진다

가변성 제한 방법

kotlin에서 가변성을 제한하기 위해서 보통 immutable(읽기전용) 객체, 컬렉션을 사용한다.

  1. val : immutable 프로퍼티 사용
  2. immutable 컬렉션 mutable 컬렉션과 구분하여 사용
  3. data class의 copy 활용하기

val : 읽기 전용 프로퍼티 사용하기

val 가 붙은 프로퍼티는 읽기 전용이지만 가변성 존재한다. 

예를 들면 mutable 객체를 담고 있을 경우가 그렇다.

 

그럼에도 var 대신 val를 권장하는 이유는 

  • 재할당이 불가능하여 동기화 문제를 줄일 수 있다.
  • val 는 var로 오버라이드가 가능하다.

가변 컬렉션과 읽기 전용 컬렉션 구분하기

읽기 전용 컬렉션 : Iterable, Collection, Set, List 등

가변 컬렉션 : 읽기 전용 컬렉션을 상속받아 변경을 위한 메서드를 추가한 Mutable** 인터페이스 

 

읽기 전용 컬렉션 안전하게 사용하는 방법

읽기 전용 컬렉션의 값을 변경할 필요가 있을 경우 -> list.toMutableList() 활용

 

data class의 copy 활용하기

Immutable한 객체가 진짜 읽기 전용으로 동작하기 위해선 해당 객체를 수정할 경우 새로운 객체를 반환해야 한다.

예 : Int의 plus, minus 메서드를 호출하면 자신을 수정한 새로운 Int 를 반환한다.

 

kotlin에서는 data class 를 활용하면 copy()를 통해 객체를 수정할 경우 내부적으로 새로운 객체를 만들어준다.


변경 가능한 컬렉션 만들 때 가변성을 줄이는 방법

// 제일 안정성이 좋은 방법
var list: List<Int> = listOf()

// 멀티스레드 처리 시 위험
val list2: MutableList<Int> = mutableListOf()

불변 프로퍼티 + 가변 컬렉션 조합의 경우 변경 가능성이 리스트 구현 내부에

위치하기 때문에 멀티스레드 처리 시 적절한 동기화가 이루어졌는지 확인하기 어렵다.

 

가변성을 제한하는 여러가지 방법들

방어적 복제(defensive copying)

class UserHolder {
    private val user: MutableUser()
    
    fun get(): MutableUser {
    	return user.copy()
    }
    
}

리턴되는 객체를 복제하는 것

 

업캐스트

data class User(val name: String)

class UserRepository {
    private val storedUsers: MutableMap<Int, String> = mutableMapOf()
    
    fun loadAll(): Map<Int, String> {
    	return storedUsers
    }
}

 

객체를 읽기 전용 슈퍼타입으로 업캐스트 하는 방법

 

결론

immutable은 불변이 아닌 읽기 전용임을 기억하고 잘 사용해야 한다.

그래도 mutable보다는 가변성이 적기 때문에 성능이 중요한 부분에서만 mutable을 사용하고 가급적이면 immutable 을 사용하여 가변성을 제한하자.

'Kotlin > 이펙티브코틀린' 카테고리의 다른 글

3장 재사용성 : 23 ~ 25  (0) 2023.08.23
2장 가독성 : Item 14 - 16  (0) 2023.08.02
item 6~10  (0) 2023.07.19