기록

[코틀린/Kotlin] 변수의 고급 기술. 상수, lateinit, lazy 본문

[Study]/Kotlin

[코틀린/Kotlin] 변수의 고급 기술. 상수, lateinit, lazy

Dannnnnn 2022. 5. 11. 00:42
반응형

변수의 다양한 사용 방법에 대해 알아보자.

 

변수에 대한 몇가지 주의할 내용과 좀 더 다른 방법으로 사용하는 것을 알아보자.

 

1. 상수

val은 할당된 객체를 변경할 수 없을 뿐이지 객체 내부의 속성을 변경할 수 없는 것은 아니다.

절대 변경이 불가능한 것은 '상수'이다.

 

컴파일 시점에 결정되어 절대 바꿀 수 없는 값이다.

 

상수로 선언될 수 있는 값은 기본 자료형만 가능하며(String 클래스 포함) 런타임에 생성될 수 있는 일반적인 다른 클래스의 객체들은 담을 수 없다.

상수는 클래스의 속성이나 지역 변수 등으로는 사용할 수 없으며, 반드시 companion object 안에 선언하여 객체의 생성과 관계없이 클래스와 관계된 고정적인 값으로만 사용하게 된다.

 

fun main() {
    
    val foodCourt = FoodCourt()
    
    foodCourt.searchPrice(FoodCourt.FOOD_CREAM_PASTA)
    foodCourt.searchPrice(FoodCourt.FOOD_STEAK)
    foodCourt.searchPrice(FoodCourt.FOOD_PIZZA)
    
}

class FoodCourt {

    fun searchPrice(foodName: String) {
        val price = when(foodName)
        {
            FOOD_CREAM_PASTA -> 13000
            FOOD_STEAK -> 25000
            FOOD_PIZZA -> 15000
            else -> 0
        }
        
        println("${foodName}의 가격은 ${price}원 입니다.")
    }
    
    companion object {
        const val FOOD_CREAM_PASTA = "크림파스타"
        const val FOOD_STEAK = "스테이크"
        const val FOOD_PIZZA = "피자"
    }
}

 

FoodCourt 클래스를 쓰는 사람들은 FoodCourt에 어떤 음식 이름이 있는지 알 방법이 없다.

 

따라서 companion object를 선언하여 내부 searchPrice()에서 사용할 음식 이름들을 상수로 선언해준다.
이것은 상수가 자주 사용되는 예이다.

 

기능적으로는 왜 굳이 변수가 아닌 상수를 별도로 사용할까?

변수의 경우 런타임시 객체를 생성하는데 시간이 더 소요되어 성능의 하락이 있기 때문이다.

따라서, 늘 고정적으로 사용할 값은 상수를 통해 객체의 생성 없이 메모리에 값을 고정하여 사용하여 성능을 향상시킬 수 있다.

 

2. 늦은 초기화

코틀린에서는 변수를 선언할 때 객체를 바로 할당하지 않는 경우(자료형만 지정해두는 경우) 기본적으로 컴파일 에러가 난다.

경우에 따라서는 변수에 객체를 할당하는 것을 선언과 동시에 할 수 없을 때도 있다.

이럴때는 lateinit 키워드를 사용하여 일단 변수만 선언하고 초기값의 할당은 나중에 할 수 있다.

 

lateinit var 변수의 제한사항

1. 초기값 할당 전까지는 변수를 사용할 수 없다. (에러 발생)

2. 기본 자료형에는 사용할 수 없다. (String 클래스는 사용 가능) 

 

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 변수의 초기화 여부를 확인할 때는 변수 이름 앞에 :: 을 붙이고 .isInitialized 라는 값을 확인해보면 초기화가 되었는지 확인하여 사용할 수 있으므로 오류를 막을 수 있다.

 

 onCreate에서 이미지를 미리 선언해놓을 때 setContentView에서 inflate하기 전까지는 이미지에 접근할 수 없다. 이럴 때 사용.

 

3. 지연 대리자 속성 (lazy delegate properties)

변수를 사용하는 시점까지 초기화를 자동으로 늦춰주는 기능이다.

이는 lateinit과 달리 val 변수에 by라는 키워드를 사용하여 lazy 라는 람다함수 형태의 초기화 함수를 사용하는 형태로, 코드에서는 선언시 즉시 객체를 생성 및 할당하여 변수를 초기화하는 형태를 갖고 있지만 실제 실행시에는 val 변수를 사용하는 시점에 초기화 과정을 진행하여 코드의 실행 시간을 최적화 할 수 있는 코드이다.

 

람다함수로 초기화가 진행되므로 함수 안에 여러개의 구문이 들어갈 수 있으며 맨 마지막 구문의 결과가 변수에 할당된다.

 

fun main() {
    
    val number: Int by lazy {
        println("초기화를 합니다")
        7
    }
    
    println("코드를 시작합니다")
    println(number)
    println(number)
    
}

 

상수, 늦은 초기화, 초기화의 지연은 상황에 따라 변수를 사용하는 방법을 좀 더 세세하게 조절할 수 있다는 장점이 있다.

 

 

 

 

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

위 강의를 보면서 개인적으로 공부한 내용을 정리하였습니다.

반응형