티스토리 뷰

반응형

개발을 하다보면 변수를 선언할때 초기에 값이나 상태를 정의하기 어려워 null로 선언하는 경우나, 필요한 시점에 초기화를 해야하는 경우가 있을것 이다. 자바와 같은 고전적인 언어들은 변수가 선언된 후 초기화되지 않으면 기본값으로 초기화 되거나 값이 할당되지 않았다는 표시로 null 값을 가지게 된다.

 

하지만 코틀린은 변수 선언 당시에 초기화를 할 것을 권고하고 있으며, 실제로도 변수 선언 당시에 초기화를 하지 않거나 nullable 타입으로 만들어주지 않으면 컴파일 에러가 발생한다. nullable 타입으로 선언해도 코틀린에선 null 초기화 사용을 추천하고 있진 않다.

 

그럼 초기에 선언해서 사용하는 변수가 아니라 늦게 초기화를 해야하는 경우는 어떻게 해야할까?

코틀린에선 늦은 초기화, 초기화 지연을 할 수 있는 lateinitlazy 프로퍼티를 제공한다.


lateinit, 늦은 초기화

코틀린에서는 변수를 선언할때 객체를 바로 할당하지 않는 경우에 기본적으로 컴파일이 되지 않는다. 경우에 따라 변수만 일단 선언하고 늦게 초기화를 해야할때 lateinit 프로퍼티를 사용할 수 있다. 

 

lateinit은 일단 미리 변수를 선언해놓고 이후에 값을 할당한다. var 변수만 사용 가능하고, 기본 자료형(Primitive Type) Int, Boolean, Double, Char 등등의 자료형에는 사용할 수 없다. 또한 getter와 setter도 사용할 수 없다.

 

lateinit이 초기화가 잘 되었는지를 알 수 있는 함수가 있는데, 초기화 확인 여부는 var 변수 이름 앞에 ::(콜론2개)를 붙이고 .isInitialized를 사용하면 된다. isInitialized로 아래 lateinit 초기화 예제를 살펴보자.

fun main() {
    val a = LateInitSample()

    println(a.getLateInitText()) // 출력 결과 : 기본값
    a.text = "새로 할당한 값"
    println(a.getLateInitText()) // 출력 결과 : 새로 할당한 값
}


class LateInitSample{
    lateinit var text: String
    
    fun getLateInitText() : String{
        if(::text.isInitialized){
            return text
        }else{
            return "기본값"
        }
    }
}

 

한가지 알아둬야할 점은 변수를 선언한 뒤 초기값 할당 전에 lateinit 변수를 사용하면 아래와 같이 초기화되지 않았다고 Exception이 발생한다.

Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property b has not been initialized

lazy, 초기화 지연

변수를 실행하는 시점까지 초기화를 자동으로 늦춰주는 지연 대리자 속성(lazy delegate properties)을 알아보자. lazy는 lateinit과 달리 val 변수를 사용해야한다. val을 사용하기에 값을 변경할 수는 없고, 호출할때 어떤식으로 선언될지 정의할 수 있도록 돕는 초기화 지연 프로퍼티라 할 수 있다.

 

lazy는 람다함수 형태의 초기화 함수를 사용하는 형태로 val 변수를 선언한 뒤, by lazy를 붙이고 람다함수를 정의해주면 된다. 이렇게 코드를 작성하면 코드상으로는 선언시에 즉시 객체를 생성 및 할당하여 변수를 초기화하는 것처럼 보이지만, 실제 실행시에는 val 변수를 사용하는 시점에 초기화가 진행하여 코드의 실행시간을 최적화할 수 있도록 한다. 람다함수로 초기화가 진행되므로 함수안에 여러개의 구문이 들어갈 수 있으며 맨 마지막 구문의 결과가 변수에 할당된다.

fun main() {
    val number : Int by lazy{
        println("초기화를 합니다")
        7
    }
    println("코드를 시작합니다")
    println(number)//호출시에 초기화 진행
    println(number)//이미 초기화해서 다시 초기화 구문 실행하지 않음
}

/* 출력 결과 */
// 코드를 시작합니다
// 초기화를 합니다
// 7
// 7

위 코드에선 number 변수를 lazy로 선언하고 출력 하는 시점에 초기화를 진행한다. 첫번째 호출땐 "초기화를 합니다"라고 출력되지만 두번째 호출때는 "초기화를 합니다"라는 출력문이 나타나지 않는다. 이미 초기화를 진행했기 때문에 두번 초기화를 하지 않는다. number 변수는 값을 다시 초기화할 수 없어서 7이라는 값이 고정된 변수로 쓰이게 된다.

 


코틀린에서 lateinit과 lazy로 초기화를 늦게하는 하도록 하는 이유는 메모리 사용을 좀더 유용하게 쓸 수 있기 위함이다. 자바를 사용할땐 상수만 적절히 잘 써주면 됐었는데, 코틀린을 시작해보니 늦은 초기화라는 처음보는 개념을 접하게 됐다. 생각보다 자주 쓰이는 구문이니 적절히 잘 사용하면 메모리를 효율적으로 사용할 수 있을것 같다.

 

  • Reference

https://www.youtube.com/watch?v=4LnpxYauzVE&list=PLQdnHjXZyYadiw5aV3p6DwUdXV2bZuhlN&index=29

반응형
댓글
공지사항