독서

[이펙티브 코틀린] 1장. 안정성

오렌지색 귤 2024. 6. 23. 23:19
반응형

아이템 1. 가변성을 제한하라

 

주요 내용

 

var, mutable 객체는 반드시 필요할 때만 사용하자.

 

코틀린에서 가변성을 제한하는 방법은 아래와 같다.

  • 읽기 전용 프로퍼티 val
  • 가변 컬렉션과 읽기 전용 컬렉션 구분하기
  • 데이터 클래스의 copy

 

찾아본 내용

 

p.16

 

plusAssign()plus()의 차이는?

 

 

plusAssign()은 동일한 mutable list 안에 원소를 삽입한다.


따라서 레퍼런스 자체는 변경되지 않으므로 val 프로퍼티로 선언이 가능하다.

 

plus()은 내부적으로 새로운 ArrayList 객체를 생성하여 반환한다.


따라서 레퍼런스 자체가 변경되므로 var 프로퍼티로 선언해야한다.

 

+++ 멀티스레드 환경에서는 동기화가 필요한 MutableList와는 달리 var List는 리스트 자체는 변경 가능하지만, 요소는 변경할 수 없으므로 멀티스레드 환경에서 더 안전하다. 그러나 새로운 리스트를 계속 생성해야 하므로 성능과 메모리 사용에 주의해야 한다.

 

 

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

 

주요 내용

 

프로퍼티보다는 지역 변수를 사용하자.

 

최대한 좁은 스코프를 갖게 변수를 사용하자.

 

 

찾아본 내용

 

p. 25

 

Kotlin Sequencesequence 블록

 

 

 

Sequence는 코틀린의 지연 컬렉션으로, 필요한 시점까지 계산을 미루는 특성을 가지고 있다.


또한 sequence 블록은 코틀린에서 시퀸스를 정의하는 데 사용되고, yield를 사용하여 시퀸스의 각 값을 하나씩 반환한다.

 

Lazy Evaluation의 작동 방식

 

  1. SequenceIterator

 

코틀린에서 Sequence는 내부적으로 Iterator를 사용한다. Sequence는 실제로 데이터를 저장하지 않으며, 대신 데이터를 생성하는 방법을 알고 있는 Iterator를 반환한다. 이 Iterator는 호출될 때마다 다음 값을 계산한다.

 

 

  1. sequence 함수의 정의

 

sequence 함수는 코틀린 표준 라이브러리에서 제공되는 함수로, Iterator를 기반으로 시퀸스를 생성한다. 이는 지연 평가의 핵심이다.

 

이 함수는 iterator 함수를 받아서 새로운 Sequence 객체를 반환한다. 이 객체의 iterator 메서드를 호출하면 제공된 iterator 함수가 호출되어 새로운 Iterator가 생성된다.

 

 

예제 : Lazy Evaluation in Sequence

 

책의 소수 생성기 예제 코드로 살펴보자. sequence 블록 내부에서 yield를 사용하여 요소를 반환하는 시점까지 계산을 미룬다.

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 }
    }
}

 

여기서 yield는 요소를 시퀸스의 다음 값으로 반환하고, 그 시점까지의 모든 계산을 미루는 역할을 한다.


따라서 primes 시퀸스의 각 요소는 실제로 필요할 때까지 계산되지 않는다.

 

 

리팩토링 이후 정상 작동하지 않는 이유

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 }
    }
}

 

캡처링 때문이라는데 디버깅 해봐도 아직 이해가 쉽지 않다.

 

 

 

 

아이템 3. 최대한 플랫폼 타입을 사용하지 말라

 

생략

 

아이템 4. inferred 타입으로 리턴하지 말라

 

생략

 

아이템 5. 예외를 활용해 코드에 제한을 걸어라

 

생략

 

아이템 6. 사용자 정의 오류보다는 표준 오류를 사용하라

 

생략

 

아이템 7. 결과 부족이 발생할 경우 null과 Failure를 사용하라

 

생략

 

 

 

아이템 8. 적절하게 null을 처리하라

 

주요 내용

 

nullable 타입은 아래 세가지 방법으로 처리한다.

  • ?., 스마트 캐스팅, Elvis 연산자 등을 활용해서 안전하게 처리
  • 오류를 throw
  • 함수 또는 프로퍼티를 리팩터링해서 nullable 타입이 나오지 않게 바꾼다

 

null로 먼저 선언이 되어야 하는 경우 lateinit 또는 Delegates.notNull을 사용하자.

 

 

찾아본 내용

 

p. 53

 

return과 throw 모두 Nothing(모든 타입의 서브타입)을 리턴하게 설계되어서 가능합니다. 더 자세한 내용은 https://bit.ly/2Gn6ftO를 참고하세요

 

 

 

p. 58

 

nullable enumNone enum의 차이

 

Nullable Enum

enum class Color {
    RED, GREEN, BLUE
}

var color: Color? = null

 

여기서 color 변수는 Color enum 값인 RED, GREEN, BLUE 중 하나일 수도 있고, null일 수도 있다.

 

None Enum

enum class Color {
    RED, GREEN, BLUE, NONE
}

var color: Color = Color.NONE

 

여기서 color 변수는 Color enum 값인 RED, GREEN, BLUE 또는 NONE일 수 있다. NONE 값은 특별히 값이 없음을 나타내기 위해 정의된 것이다.

 

 

 

아이템 9. use를 사용하여 리소스를 닫아라

 

생략

 

 

아이템 10. 단위 테스트를 만들어라

 

궁금증

다른 회사에서는 보통 서비스에 주입된 컴포넌트가 몇개정도인가?

 

많으면 단위테스트를 위해 포트 인터페이스나 모듈 컴포넌트로 묶어내는 경우도 존재하는가?

반응형