DevSoupe
  • 🙂welcome
    • Hi there, I'm Seth!
  • ✍️blog
    • macOS 개발 환경 설정
    • SDKMAN!으로 자바 버전 관리
    • 도커 환경에서 MySQL 설치 및 접속
    • 도커를 사용하여 GitLab Runner 구성
    • 스프링부트 H2 DB mem 모드 사용시 테이블 접근
    • Git 서브모듈 삭제
  • 📚Book
    • 자바에서 코틀린으로 (코틀린으로 리팩터링하기)
      • 1장 - 소개
      • 2장 - 자바 프로젝트에서 코틀린 프로젝트
      • 3장 - 자바 클래스에서 코틀린 클래스로
      • 4장 - 옵셔널에서 널이 될 수 있는 타입으로
    • 오브젝트 (코드로 이해하는 객체지향 설계)
    • 이펙티브 코틀린
      • 1장 - 안정성
        • 아이템 1 - 가변성을 제한하라
        • 아이템 2 - 변수의 스코프를 최소화하라
        • 아이템 3 - 최대한 플랫폼 타입을 사용하지 말라
        • 아이템 4 - inferred 타입으로 리턴하지 말라
        • 아이템 5 - 예외를 활용해 코드에 제한을 걸어라
        • 아이템 6 - 사용자 정의 오류보다는 표준 오류를 사용하라
        • 아이템 7 - 결과 부족이 발생할 경우 null과 Failure를 사용하라
        • 아이템 8 - 적절하게 null을 처리하라
        • 아이템 9 - use를 사용하여 리소스를 닫아라
        • 아이템 10 - 단위 테스트를 만들어라
  • 🧑‍🏫Seminar
    • 우아한 모노리스
    • 우아한 객체지향
    • 점진적 추상화
  • 🌎English
    • 영어 피트니스 50일의 기적 ①
      • PART 1 워밍업
        • 1. '말문 트기'란?
      • PART 2 말문 트기 훈련 코스
        • DAY 1
          • STEP 1. Do (~해, ~하지 마)
          • STEP 2. Do + 말늘리기
    • 라이브 아카데미 토들러
      • Lesson 001 - 기본적인 문장 구성하기
      • Lesson 002 - 문장 만들기
Powered by GitBook
On this page
  • 캡쳐링
  • 정리
  1. Book
  2. 이펙티브 코틀린
  3. 1장 - 안정성

아이템 2 - 변수의 스코프를 최소화하라

아이템 2 - 변수의 스코프를 최소화하라를 정리한 내용입니다.

  • 상태 정의시 변수, 프로퍼티의 스코프를 최소화하는 것이 좋다.

  • 프로퍼티 보다는 지역 변수를 사용하도록 한다.

  • 최대한 좁은 스코프를 갖게 변수를 사용하도록 한다.

  • 코틀린의 스코프는 기본적으로 중괄호로 만들어진다.

val a = 1
fun fizz() {
    val b = 2
    print(a + b)
}
val buzz = {
    val c = 3
    print(a + c)
}
// 여기서는 a는 사용 가능하나, b와 c는 사용할 수 없다.
- 외부에서 내부 스코프의 요소에 접근할 수 없다.
- 내부에서는 외부의 스코프 요소에 접근할 수 있다.
// 나쁜 예
var user: User
for (i in users.indices) {
    user = users[i]
    print("User at $i is $user)
}
// 조금 더 좋은 예
for (i in users.indicies) {
    val user = users[i]
    print("User at $i is $user)
}
// 제일 좋은 예
for (i, user) in users.withIndex()) {
    print("User at $i is $user")
}
- 스코프를 내/외부에서 사용할 수 있게 하는건 좋지 않다.
  • 스코프를 좁게 만들면 프로그램을 추적하고 관리하기 쉽다.

  • 프로그램의 변경 포인트가 많으면 프로그램을 이해하기 어려워진다.

  • mutable 프로퍼티의 스코프가 넓어지면 코드를 이해하기 어려워진다.

  • 변수는 if, when, try-catch, Elvis를 표현식들을 활용해 가능한 정의할 때 초기화 하는 것이 좋다.

// 나쁜 예
val user: User
if (hasValue) {
    user = getValue()
} else {
    user = User()
}
// 조금 더 좋은 예
val user: User = if (hasValue) {
    getValue()
} else {
    User()
}
// 나쁜 예
fun updateWeather(degrees: Int) {
    val description: String
    val color: Int
    if (degrees < 5) {
        description = "cold"
        color = Color.BLUE
    } else if (degrees < 23) {
        description = "mild"
        color = Color.YELLOW
    } else {
        description = "hot"
        color = Color.RED
    }
}
// 조금 더 좋은 예
fun updateWeather(degrees: Int) {
    val (description, color) = when { // destructuring declaration 활용
        degrees < 5 -> "cold" to Color.BLUE
        degrees < 23 -> "mild" to Color.YELLOW
        else -> "hot" to Color.RED
    }
}

캡쳐링

  • 에라토스테네스의 체(소수를 구하는 알고리즘)를 구현해본다.

var numbers = (2..100).toList()
val primes = mutableListOf<Int>()
while (numbers.isNotEmpty()) {
    val prime = numbers.first()
    primes.add(prime)
    numbers = number.filter { it % prime != 0 }
}
print(primes) // [2, 3, 5, 7, 11, ..., 71, 73, 79, 83, 89, 97]
1. 2부터 100까지 숫자 리스트를 만든다.
2. 첫 번째 요소를 선택한다. (소수)
3. 남아 있는 수를 2번에서 선택한 소수로 나누어지는 모든 숫자를 제거한다. (반복)
  • 시퀀스를 활용해 소수 구하는 프로그램을 구현해본다.

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]
반복
first() 호출시 numbers 함수 체인
함수 체인에 걸리지는 값
prime

1

없음

없음

2

2

drop(1).filter { it % 2 != 0 }

drop 2

3

3

drop(1).filter { it % 2 != 0 }

drop(1).filter { it % 3 != 0 }

drop 2, filter 4 drop 3

5

4

drop(1).filter { it % 2 != 0 }

drop(1).filter { it % 3 != 0 } drop(1).filter { it % 5 != 0 }

drop 2, filter 4, 6 drop 3, drop 5

7

5

drop(1).filter { it % 2 != 0 }

drop(1).filter { it % 3 != 0 } drop(1).filter { it % 5 != 0 } drop(1).filter { it % 7 != 0 }

drop 2, filter 4, 6, 8, 10 drop 3, filter 9 drop 5 drop 7

11

...

3, 17, 19, 23, 29

  • 시퀀스의 지연연산으로 인해 prime 변수가 최종값으로 캡쳐 되었을때는 전혀 다른 결과가 나온다.

val primes: Sequence<Int> = sequence {
    var numbers = generateSequence(2) { it + 1 }
    
    var prime
    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]
반복
first() 호출시 numbers 함수 체인
함수 체인에 걸리지는 값
prime

1

없음

없음

2

2

drop(1).filter { it % 2 != 0 }

drop 2

3

3

drop(1).filter { it % 3 != 0 }

drop(1).filter { it % 3 != 0 }

drop 2, filter 3 drop 4,

5

4

drop(1).filter { it % 5 != 0 }

drop(1).filter { it % 5 != 0 } drop(1).filter { it % 5 != 0 }

drop 2, filter 5 drop 3, drop 4,

6

5

drop(1).filter { it % 6 != 0 }

drop(1).filter { it % 6 != 0 } drop(1).filter { it % 6 != 0 } drop(1).filter { it % 6 != 0 }

drop 2, filter 6 drop 3, drop 4, drop 5,

7

...

8, 9, 10, 11, 12

- 람다식 안에서의 변수 캡쳐 문제는 주의해야 한다.

정리

변수의 스코프는 좁게 만들어서 사용하는 것이 좋다.

var 보다는 val을 사용하는 것이 좋다.

람다에서 변수를 캡처한다는 사실을 꼭 기억해야 한다.

Last updated 8 months ago

📚