아이템 01. 가변성을 제한하라. #
val #
val
은 읽기 전용 프로퍼티지만, immutable 을 의미하는 것은 아니다. setter 를 제공하지 않을 뿐이다. (혼동하지 말 것)
immutable 이 필요하다면 final
키워드를 사용한다.
컬렉션 다운캐스팅 #
컬렉션 다운캐스팅은 계약을 위반하고, 추상화를 무시하는 행위다.
아래는 컬렉션 다운캐스팅의 간단한 예시이다.
val list = listOf(1,2,3)
if (list is MutableList) {
list.add(4)
}
JVM에서 listOf 는 자바의 List 인터페이스를 구현한 Array.ArrayList
객체를 리턴한다.
자바의 List 인터페이스는 add, set 과 같은 메서드를 제공하니까 코틀린에서 MutableList
로 변경될 수 있다.
하지만 Arrays.ArrayList
이런 연산을 구현하고 있지 않아 오류가 발생한다.
즉, 위 코드의 문제는 플랫폼이나 내부 구현 버전(예를 들어, java/kotlin 언어의 버전 업그레이드)마다 결과가 달라질 수 있다.
" ‘시스템 해킹’을 시도해서 다운캐스팅을 할 때 문제가 됩니다. 실제로 코틀린 프로젝트를 진행할 때, 이는 허용해서는 안 되는 큰 문제입니다. “
immutable 객체로부터 mutable 객체가 필요한 경우 #
immutable 객체에 write 작업이 필요한 경우,
- 복제(copy)를 통해서 새로운 mutable 객체를 만들어 반환,사용한다.
- 새로운 객체를 만들어 반환,사용한다.
다른 종류의 변경 가능 지점 #
변경 가능한 컬렉션을 사용할 때 다음과 같은 조합으로 사용할 수 있다.
- val + mutable 컬렉션
- var + immutable 컬렉션
- var + mutable 컬렉션
- 사용/비교하지 않는다.
(다른 종류의 변경 가능 지점) 예시 1. val + mutable 컬렉션 #
val list = mutableListOf<Int>()
list.add(1)
println(list) // [1]
list += 2 // list.plusAssign(2)로 변경된다.
println(list) // [1, 2]
(다른 종류의 변경 가능 지점) 예시 2. var + immutable 컬렉션 #
var list = listOf<Int>()
list = list + 1
println(list) // [1]
list += 2 // list.plus(2)로 변경된다.
println(list) // [1, 2]
기준 | 특징 |
---|---|
val + mutable 컬렉션 | 변경 지점/코드가 컬렉션 구현 내부에 있다. 멀티스레드 처리가 이루어질 경우, 내부적으로 적절한 동기화가 되어 있는지 확실하게 알 수 없으므로 위험하다. |
var + immutable 컬렉션 | 변경 지점/코드가 우리 코드에 있다. 멀티스레드 처리 안정성이 더 좋다고 할 수 있다. (즉, 우리가 직접 제어하기 편하다.) 예시 1: (우리가 관리하는 코드라면) 값이 변경될 때 Delegates.observable 를 사용해서 log를 추가하거나 이벤트를 발행하거나 등의 추가적인 행위를 쉽게 덧붙일 수 있다.예시 2. setter 를 private 으로 만들 수 있다. “물론 잘못 만들면 일부 요소가 손실될 수 있다” 고 설명한다. |
” mutable 컬렉션에도 observable 하게 만들 수 있지만 추가적인 구현이 필요하다. 따라서 mutable 프로퍼티에 immutable 컬렉션을 사용하는 것이 더 쉽다. “
(Q) 내부적으로 구현된 컬렉션이 어떤 타입인지 정확히 알고 있다면 구현된 컬렉션을 사용하는 것이 더 좋지 않을까?
사용자가 개발한 코드에 오류가 발생하기 더 쉽지 않을까?
변경 가능 지점 노출하지 말기 #
(한 줄 요약) mutable 객체를 외부에 노출하는 것은 굉장히 위험하다.
mutable 객체를 외부에 노출하고 싶다면 아래와 같이 처리할 수 있다.
(1) 방어적 복제(copy)
(2) immutable 반환
요약 #
- val, final 혼동하지 말 것
- 컬렉션 다운캐스팅 하지말 것
- 쓰기가 필요한 컬렉션을 프로퍼티로 가질 때
var + immutable 컬렉션
조합으로 사용하자.
최근에 관련해서 고민한 부분이 있었는데 도움이 됐다.