[Kotlin]지연초기화-lateinit/lateinit과 by lazy의 차이

dada·2021년 8월 27일
1

Kotlin

목록 보기
11/14
post-thumbnail

🏃‍♂️공부하기 앞서!

  • 코틀린은 기본적으로 Non-null타입을 가짐
  • 따라서 항상 변수를 선언할때 null값이 아닌 이상 값을 초기화해야 에러가 안남
fun late() {
    //var name2:String 코틀린에서는 null이 아닌 이상 초기화해주지 않으면 에러발생
    var namecheck: String = ""
    var nullName: String?=null
}

💬lateinit

  • 개발을 하다 보면 클래스 안의 변수를 nullable로 선언 후 초기화를 나중에 해야하는 경우가 있는데, 이럴 경우 변수값을 클래스의 다른 속성이 사용할 때 ?.로 계속 체크해서 사용해야 하니 코드가 깔끔하지 못하다 ㅠㅠ
class Sport{
    var name:String?=null //null로 미리 선언해두고 나중에 초기화 하려함
    fun process(){
        name?.plus("메시")  //근데 처음에 null로 매번 초기화하면 매번 ?.로 체크해줘야됨
    }
}
  • 이때 사용하는게 타입선언은 미리 해두고 나중에 값을 초기화하는 '지연 초기화'이다.
  • 초기화를 늦추면 좋은 점이 또 하나 있는데, 사용할지 모르는 데이터를 미리 초기화할 필요가 없어서 성능 향상에 도움이 된다. 예를 들어, Rest API로 GitHub의 데이터를 가져오는 기능이 있는데, 앱이 실행했을 때 미리 가져오는 것보다 데이터를 화면에 보여줄 때 가져오는 것이 CPU 자원도 아끼고, 네트워크 자원도 아낄 수 있다.
  • 코틀린에서 제공하는 초기화 지연은 다음과 같은 것들이 있다.
  • Late initialization : 필요할 때 초기화하고 사용할 수 있음. 초기화하지 않고 쓰면 Exception 발생
  • Lazy initialization : 변수를 선언할 때 초기화 코드도 함께 정의. 변수가 사용될 때 초기화 코드 동작하여 변수가 초기화됨

✅lateinit

  • late initialization은 var 앞에 lateinit을 붙여 변수를 선언하면 된다. late라는 말에서 코드를 늦게 초기화한다는 의미이다
class Rectangle {
    lateinit var area: Area
    fun initArea(param: Area): Unit {
        this.area = param
    }
}

class Area(val value: Int)

fun main() {
    val rectangle = Rectangle()
    rectangle.initArea(Area(10))
    println(rectangle.area.value)
}
  • 위의 코드에서는 lateinit var area로 선언하고 초기값을 지정하지 않았다. 이 변수는 nullable이 아니기 때문에 초기값을 할당하지 않으면 에러가 발생합니다. 하지만 lateinit를 붙여 나중에 초기화하겠다고 컴파일러에게 말했기 때문에 컴파일 에러가 발생하지 않는다.

  • rectangle.initArea(Area(10))로 늦게 변수를 초기화하고 그 다음 줄에 Area 객체를 사용하고 있다. 만약 초기화를 하지 않고 Area 변수에 접근하면 UninitializedPropertyAccessException이 발생

✅ lateinit의 특징

  • lateinit은 var에만 사용할 수 있다.
  • primitive type에 적용할 수 없다. primitive type은 Int, Boolean, Double 등의 코틀린에서 제공하는 기본적인 타입. 따라서, 아래처럼 val을 사용하거나, Int를 사용한 코드는 컴파일 에러가 발생.
lateinit val area : Area    // compile error
lateinit var width : Int    // compile error
  • 그리고 lateinit 프로퍼티는 custom getter/setter를 설정할 수 없다.
  • non-null 프로퍼티만 사용이 가능합니다. 따라서, 아래의 코드들은 컴파일이 안됨.
lateinit var area: Area?    // compile error

lateinit var area: Area     // compile error
  get() {
      area;
  }
  • lateinit의 특징
    1.var 프로퍼티만 사용 가능
    2.primitive type(Int, Boolean)은 사용할 수 없음
    3.Custom getter/setter를 만들 수 없음
    4.Non-null 프로퍼티만 사용 가능

✅ by Lazy

  • Lazy라는 말에서 초기화를 미룰 수 있을 만큼 미루고 어쩔 수 없이 초기화를 해야하는 상황이 올 때 초기화를 한다는 것.

  • Lazy initialization은 프로퍼티를 정의할 때 초기화 코드도 함께 정의.
    그리고 프로퍼티가 처음 사용될 때 초기화 구문이 실행되면서 초기값이 할당

  • 초기값 대신에 by lazy { ... }를 입력.

  • { ... } 부분은 변수가 처음 사용될 때 한번 호출되며 마지막의 값이 초기값으로 할당. 아래 예제에서는 balance에 100이 할당됨

  • 중요한 것은 {...}는 처음 사용할 때 한번만 호출되고 두번째 사용할 때는 호출되지 않는다는 것

class Account() {
    val balance : Int by lazy {
        println("Setting balance!")
        100
    }
}

fun main() {
    val account = Account()
    println(account.balance)
    println(account.balance)
}
  • lazy init의 특징
    1.val 프로퍼티만 사용할 수 있음
    2.primitive type(Int, Boolean 등)도 사용 가능
    3.Non-null, Nullable 모두 사용 가능
profile
'왜?'라는 물음을 해결하며 마지막 개념까지 공부합니다✍

0개의 댓글