가변성을 제한하라
-
if(name != null) 등의 조건문을 사용해서 null인지 검사해주면 조건문 본문 내부에서는 name이 null이 아니라는 것인지 확인이 되었기 때문에 String?을 String 타입으로 스마트 캐스팅 해준다 null 확인 이외에도 여러 타입 비교에도 활용 가능하다.
-
읽기 전용으로(val) 선언했을 경우 사용자 정의 getter를 가지고 있다면 스마트 캐스팅이 불가능 하다. getter를 사용하는 시점의 getter를 받는 부분의 프로퍼티나 변수의 값에 따라서 다른 결과가 나올 수 있기 때문이다.
- 코틀린에서 읽기 전용 컬렉션을 mutable하게 다운 캐스팅을 하면 안된다.
-
읽기 전용에서 mutable로 다운캐스팅 해야한다면 toMutableList와 같은 copy를 사용해야 한다.
Ex) 절대 사용하지 말아야 할 코드 예시
val list = listOf(1, 2, 3) if(list is MutableList) { list.add(4) }
val list = listOf(1, 2, 3) val mutableList = list.toMutableList() mutableList.add(4)
요렇게 사용해야 한다!
- 한 번 정의된 상태가 유지되므로 코드를 이해하기 쉬워진다.
- Immutable 객체는 공유했을 때 충돌이 발생하지 않으므로 병렬 처리를 안전하게 진행할 수 있다.
- Immutable 객체에 대한 참조는 변경되지 않으므로 쉽게 캐시 가능하다.
- Immutable 객체는 방어적 복사본을 만들 필요가 없다. -> 깊은 복사를 따로 수행 해 줄 필요가 없다.
최악의 코드 예시
var list3 = mutableListOf<Int>()
이렇게 코드를 작성하면, 변경될 수 있는 두 지점 모두에 대한 동기화를 구현해야 한다. 또한 모호성이 발생하여 += 연산자를 사용할 수 없게 된다.
중간 요약 : 상태를 변경할 수 있는 불필요한 방법은 만들지 않아야 한다. 상태를 변경하는 모든 방법은 코드를 이해하고 유지해야 하므로 비용이 발생하게 되고, 이를 막기 위해 가변성을 최대한 제한하는 것이 좋다.