1장은 안정성을 주제로 10가지 아이템을 다루고 있다.
Item 1 : 가변성을 제한하라
가변성을 제한하는 이유
- 많은 부분에서 변화가 생기면 디버깅이 어려워진다
- 테스트하기 어렵다
- 멀티스레드 환경일 경우 동기화가 필요한데, 변경이 많을수록 충돌 지점도 많아진다
가변성 제한 방법
kotlin에서 가변성을 제한하기 위해서 보통 immutable(읽기전용) 객체, 컬렉션을 사용한다.
- val : immutable 프로퍼티 사용
- immutable 컬렉션 mutable 컬렉션과 구분하여 사용
- 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 |