일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 객체
- 안드로이드 레트로핏 사용법
- 자바 다형성
- 서비스 쓰레드 차이
- 안드로이드 라이선스 종류
- 클래스
- 안드로이드 레트로핏 crud
- 안드로이드 유닛 테스트
- rxjava disposable
- ANR이란
- 안드로이드 os 구조
- 멤버변수
- android ar 개발
- rxjava hot observable
- 안드로이드 라이선스
- 2022 플러터 안드로이드 스튜디오
- 안드로이드 유닛테스트란
- 안드로이드 유닛 테스트 예시
- 2022 플러터 설치
- rxjava cold observable
- 서비스 vs 쓰레드
- android retrofit login
- 스택 자바 코드
- Rxjava Observable
- 플러터 설치 2022
- jvm이란
- 스택 큐 차이
- jvm 작동 원리
- ar vr 차이
- 큐 자바 코드
- Today
- Total
나만을 위한 블로그
[이펙티브 코틀린] 아이템 2. 변수의 스코프를 최소화하라 본문
상태를 정의할 때는 변수와 프로퍼티의 스코프를 최소화하는 게 좋다.
- 프로퍼티보다는 지역 변수를 쓰는 게 좋다
- 최대한 좁은 스코프를 갖게 변수를 사용한다. 예를 들어 반복문 안에서만 변수가 쓰인다면 변수를 반복문 안에 작성하는 게 좋다
요소의 스코프 : 요소를 볼 수 있는 컴퓨터 프로그램 영역. 코틀린의 스코프는 기본적으로 중괄호로 만들어지며 내부 스코프에서 외부 스코프에 있는 요소에만 접근할 수 있다.
fun main() {
val a = 1
fun fizz() {
val b = 2
println("a + b : ${a + b}")
}
val buzz = {
val c = 3
print("a + c : ${a + c}")
}
}
위 예시에서 fizz, buzz()의 스코프에선 외부 스코프에 있는 변수에 접근할 수 있다. 하지만 외부 스코프에선 내부 스코프에 정의된 변수에 접근할 수 없다.
아래는 변수 스코프를 제한하는 예시다. (main 위의 2줄은 내가 임의로 추가했다)
class User(val name: String)
val users = listOf(User("a"), User("b"), User("c"))
fun main() {
// 나쁜 예
var user: User
for (i in users.indices) {
user = users[i]
println("User at $i is ${user.name}")
}
// 좀 더 좋은 예
for (i in users.indices) {
val user = users[i]
println("User at $i is ${user.name}")
}
// 제일 좋은 예
for ((i, user) in users.withIndex()) {
println("User at $i is ${user.name}")
}
}
1번 예에서 변수 user는 for문 내부, 외부에서도 쓸 수 있지만 2, 3번 예에선 user의 스코프를 for문 내부로 제한한다. 최대한 변수는 스코프를 좁게 설정하는 게 좋다.
스코프를 좁게 만드는 가장 중요한 이유 : 프로그램 추적, 관리가 쉽기 때문
변수 스코프 범위가 너무 넓으면 다른 개발자에 의해 변수가 잘못 쓰일 수 있다. 다른 개발자가 이걸 써서 코드를 구성하면 또 다른 개발자들이 이 코드를 이해하기 어려울 것이다.
변수는 읽기 전용, 읽고 쓰기 전용 여부와 상관없이 변수를 정의할 때 초기화되는 게 좋다. if, when, try-catch, Elvis 표현식을 활용하면 최대한 변수를 정의할 때 초기화할 수 있다
fun main() {
// 나쁜 예
val user: User
if (hasValue) {
user = getValue()
} else {
user = User()
}
// 조금 더 좋은 예
val user: User = if (hasValue) {
getValue()
} else {
User()
}
}
여러 프로퍼티를 한꺼번에 설정해야 하는 경우엔 구조분해 선언(destructuring declaration)을 활용하는 게 좋다.
fun main() {
// 나쁜 예
fun updateWeather(degrees: Int) {
val description: String
val color: Int
if (degrees < 5) {
description = "cold"
color = BLUE
} else if (degrees < 23) {
description = "mild"
color = YELLOW
} else {
description = "hot"
color = RED
}
// ...
}
// 좀 더 좋은 예
fun updateWeather2(degrees: Int) {
val (description, color) = when {
degrees < 5 -> "cold" to BLUE
degrees < 23 -> "mild" to YELLOW
else -> "hot" to RED
}
}
}
결론 : 변수 스코프가 넓으면 위험하다
캡쳐링
시퀀스 빌더를 써서 에라토스테네스의 체(소수 구하는 알고리즘)를 구현하란 문제가 있다. 알고리즘 자체는 개념적으로 단순하다.
- 2부터 시작하는 숫자 리스트(2..100 등)를 만든다
- 1번째 요소를 선택한다. 2기 때문에 소수다
- 남아있는 숫자 중 2번에서 선택한 소수로 나눌 수 있는 모든 숫자를 제거한다
이걸 구현하면 아래와 같다.
fun main() {
var numbers = (2..100).toList()
val primes = mutableListOf<Int>()
while(numbers.isNotEmpty()) {
val prime = numbers.first()
primes.add(prime)
numbers = numbers.filter {
it % prime != 0
}
}
print(primes)
// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
}
아래는 시퀀스를 활용하는 방식으로 확장한 것이다.
fun main() {
val primes: Sequence<Int> = sequence {
var numbers = generateSequence(2) { it + 1 }
while (true) {
val prime = numbers.first()
yield(prime)
numbers = numbers.drop(1)
.filter { it % prime != 0 }
}
}
print(primes.take(10).toList())
// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
}
이걸 최적화하려는 사람들은 항상 존재한다. prime을 var로 선언하고 반복문 안에서 계속 만드는 게 아니라 반복문 진입 전에 1번만 생성하는 형태다.
fun main() {
val primes: Sequence<Int> = sequence {
var numbers = generateSequence(2) { it + 1 }
var prime: Int
while (true) {
prime = numbers.first()
yield(prime)
numbers = numbers.drop(1)
.filter { it % prime != 0 }
}
}
print(primes.take(10).toList())
// [2, 3, 5, 6, 7, 8, 9, 10, 11, 12]
}
그러나 실행 결과는 이상하다. 이런 결과가 나온 이유는 prime 변수를 캡쳐했기 때문이다.
이런 문제가 발생할 수 있어 항상 잠재적인 캡쳐 문제를 주의해야 한다. 가변성을 피하고 스코프 범위를 좁게 만들면 이런 문제를 간단하게 피할 수 있다.
'책 > Effective Kotlin' 카테고리의 다른 글
[이펙티브 코틀린] 아이템 6. 사용자 정의 오류보다는 표준 오류를 사용하라 (0) | 2022.05.26 |
---|---|
[이펙티브 코틀린] 아이템 5. 예외를 활용해 코드에 제한을 걸어라 (0) | 2022.05.22 |
[이펙티브 코틀린] 아이템 4. inferred 타입으로 리턴하지 마라 (0) | 2022.05.15 |
[이펙티브 코틀린] 아이템 3. 최대한 플랫폼 타입을 사용하지 마라 (0) | 2022.05.08 |
[이펙티브 코틀린] 아이템 1. 가변성을 제한하라 (0) | 2022.05.07 |