728x90
- 코틀린의 프로퍼티는 자바의 필드와 비슷해보이지만 서로 다른 개념
// 코틀린의 프로퍼티
var name: String? = null
// 자바의 필드
String name = null;
- 둘다 데이터를 저장
- 코틀린 프로퍼티에는 더 많은 기능이 있음
- 사용자 정의 세터와 게터를 가질 수 있음
var name: String? = null get() = field?.toUpperCase() set(value) { if (!value.isNullOrBlank()) { field = value } }
- field 식별자는 프로퍼티의 데이터를 저장해 두는 백킹 필드에 대한 레퍼런스
- 세터와 게터의 디폴트 구현에 사용되므로, 따로 만들지 않아도 디폴트로 생성
- val을 사용해서 읽기 전용 프로퍼티를 만들 대는 field가 만들어지지 않음
val fullName: String get() = "$name $surname"
- var를 사용해서 만든 읽고 쓸 수 있는 프로퍼티는 게터와 세터를 정의할 수 있음
- 파생 프로퍼티라고 부르며 자주 사용됨
- 자바 표준 라이브러리 Date를 활용해 객체에 날짜를 저장해서 많이 활용한 상황
- 직렬화 문제 등으로 객체를 더 이상 이러한 타입으로 저장할 수 없음
- 데이터를 millis라는 별도의 프로퍼티로 옮기고, 이를 활용해서 date 프로퍼티에 데이터를 저장하지 않고, 랩/언랩 하도록 코드를 변경하면 됨
var date: Date get() = Date(millis) set(value) { millis = value.time }
- 프로퍼티는 필드가 필요 없음
- 프로퍼티는 개념적으로 접근자(val은 게터, var은 게터와 세터)를 나타냄
- 코틀린은 인터페이스에도 프로퍼티를 정의할 수 있음
interface Person {
val name: String
}
- 인터페이스를 오버라이드 할 수 있음
open class Supercomputer {
open val theAnswer: Long = 42
}
class AppleComputer: Supercomputer() {
override val theAnswer: Long = 1_800_276_2273
}
- 프로퍼티를 위임할 수 있음
- 아이템 21에서 자세히 설명
val db: Database by lazy { connectToDb() }
- 프로퍼티는 본질적으로 함수이므로, 확장 프로퍼티를 만들 수 있음
val Context.preferences: SharedPreferences
get() = PreferenceManager.getDefaultSharedPerferences(this)
val Context.inflater: layoutInflater
get() = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val Context.notificationManager: Notificationmanager
get() = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- 프로퍼티로 다음과 같이 알고리즘의 동작을 나타내는 것은 좋지 않음
- 이런 프로퍼티는 여러 가지 오해를 불러일으킬 수 있음
var Tree<Int>.sum: Int get() = when (this) { is Leaf -> value is Node -> left.sum + right.sum }
- 프로퍼티가 아닌 함수로 구현해야 함
var Tree<Int>.sum: Int
get() = when (this) {
is Leaf -> value
is Node -> left.sum + right.sum
}
- 어떤 것을 프로퍼티로 해야하는지 판단할 수 있는 질문
- 이 프로퍼티를 함수로 정의할 경우, 접두사로 get 또는 set을 붙일 것인가?
- 아니라면 프로퍼티로 만드는 것이 좋지 않음
- 프로퍼티 대신 함수를 사용하는 것이 좋은 경우
- 연산 비용이 높거나 복잡도가 O(1)보다 큰 경우
- 연산 비용이 많이 들어간다면 함수를 사용하는 것이 좋음
- 사용자가 연산 비용을 예측하기 쉽고, 이를 기반으로 캐싱 등을 고려할 수 있음
- 비즈니스 로직을 포함하는 경우
- 코드를 읽을 때 프로퍼티가 로깅, 리스너 통지, 바인드된 요소 변경과 같은 단순한 동작 이상을 할 거라고 기대하지 않음
- 결정적이지 않은 경우
- 같은 동작을 연속적으로 두 번 했는데 다른 값이 나올 수 있는 경우 함수가 좋음
- 변환의 경우
- 변환을 프로퍼티로 만들면 오해를 불러 일으킬 수 있음
- 게터에서 프로퍼티의 상태 변경이 일어나야 하는 경우
- 게이터에서 프로퍼티의 상태 변화를 일으킨다고 생각하지 않음
- 연산 비용이 높거나 복잡도가 O(1)보다 큰 경우
- 요소의 합계를 계산하려면, 모든 요소를 더하는 반복 처리가 필요
- 선형 복잡도를 가지므로, 프로퍼티가 아니라 함수로 정의하는 것이 좋음
val s = (1..100).sum()
- 상태를 추출/설정할 때는 프로퍼티를 사용해야 함
// 이렇게 하지 마세요!!
class UserIncorrect {
private var name: String = ""
fun getName() = name
fun setName(name: String) {
this.name = name
}
}
class UserCorrect {
var name: String = ""
}
728x90
'코틀린 스터디 > 이펙티브 코틀린' 카테고리의 다른 글
아이템18) 코딩 컨벤션을 지켜라 (0) | 2024.04.17 |
---|---|
아이템17) 이름 있는 아규먼트를 사용하라 (0) | 2024.04.17 |
아이템15) 리시버를 명시적으로 참조하라 (0) | 2024.03.19 |
아이템14) 변수 타입이 명확하지 않은 경우 확실하게 지정하라 (0) | 2024.03.19 |
아이템13) Unit?을 리턴하지 말라 (0) | 2024.03.12 |