Kotlin (코틀린)

[Kotlin] 코틀린 늦은 초기화 기법 - lateinit / lazy

Oscar:) 2024. 5. 8. 20:00

 

 

이번 포스팅에서는 늦은 초기화 기법에 대해 알아본다.

 

 

 


 

늦은 초기화 기법?

 

 

말 그대로 객체 초기화를 늦게 하는 방법이다.

 

가끔 객체의 선언과 초기화 시점이 달라야할 때가 있다.

대부분 변수를 미리 선언해놓고, 초기화는 나중에(필요한 시점에) 하는 경우다.

 

 

그런 상황에서 단순히 다음과 같이 해결할 수 있다.

var name = null
or
var name : String? = null


// 초기화 시점
name = "Oscar"

 

하지만, 위 방법은 사실 좋지 않은 방법이라고 볼 수 있다.

 

 

이전 코틀린 관련 포스팅 중, 코틀린 특징 파트에서 NPE에 대한 안정성을 언급했었다.

 

[Kotlin] 코틀린 입문 / 코틀린이란? / 코틀린 특징

OscarStory.. 코틀린으로 진화..!    사실 2~3년 전까지만 해도 검색 결과들이 자바를 사용한 레퍼런스가 대부분이었고,안드로이드 공식문서에서조차 자바로 짜여진 예제를 더 많이 찾아볼 수 있

oscarstory.tistory.com

 

 

 

코틀린에서는 null이 될 수 있는 가능성만 있어도 해당 객체를 추적하는데,

가능성은 커녕 대놓고 null을 박아버리면... 코틀린의 의도를 많이 벗어난다고 볼 수 있다.

 

그렇기에 위와 같은 행동은 되도록이면 지양해야 하고,

이러한 상황에서 우리는 늦은 초기화 기법을 사용하면 된다.

 

 

 

코틀린에서 소개하는 늦은 초기화 기법은 다음과 같이 2가지가 있다.

 

✅ lateinit

✅ lazy

 

 

하나씩 알아보자.

 

 

 


 

lateinit

 

 

lateinit은 다음과 같이 사용한다.

// 늦은 초기화 선언
lateinit var str : String

// 초기화 시점
str = "Oscar"

 

 

늦은 초기화를 하는 대신, 반드시 타입을 명시해주어야 한다.

 

 

위처럼 타입을 명시하지 않은 경우에는 에러를 표시한다.

 

 

타입을 명시해주면 ↓

 

편-안

 

 

 

✅ lateinit 특징

 

● var 로만 선언할 수 있다.

사실, 늦은 초기화라는 것부터 값이 나중에 변경되는 느낌이라 val은 사용할 수 없는 것이다.

 

● 반드시 타입을 명시해야 한다.

위에서도 언급했지만, 타입을 명시하지 않으면 컴파일할 수조차 없다.

 

● 메서드, 생성자 내에서 사용할 수 없다.

보통 클래스 단위의 전역 변수로 사용한다.

 

● 선언할 때 null을 대입할 수 없다.

이는 늦은 초기화를 사용하는 이유이기도 하기 때문에, 당연하다고 생각했으면 좋겠다.

 

● 기존 원시 타입에는 사용할 수 없다.

Int, Double, Boolean 등에는 사용할 수 없다.

 

● lateinit을 사용했다면 반드시 초기화를 해줘야 한다.

당연한 이야기일 수 있지만, "나중에 초기화할게~" 라고 약속해놓고

초기화를 안 한 상태로 컴파일하면 에러를 뿜어낸다.

 

 

 

 


 

lazy

 

 

lazy는 다음과 같이 사용한다.

문법)
val 변수명 by lazy { 초기화 구문 }

예시)
val name = "Oscar"
val textLength by lazy { name.length }

println(textLength) // lazy 초기화 시점!!!

// 출력 결과 : 5

 

by lazy 이후의 구문은 해당 객체가 사용될 때 동작한다.

즉, lazy 적용한 객체를 호출 시에 초기화할 구문을 작성한다고 생각하면 된다.

 

 

근데 사실, name 변수가 초기화되어있기 때문에 lazy를 위처럼 사용할 이유는 없다.

 

 

다음과 같은 상황이라면 lazy를 알맞게 사용했다고 할 수 있다.

lateinit var name : String
val textLength : Int by lazy { name.length }

// 대충 다른 작업

name = "Oscar"
println(textLength) // lazy 초기화 시점!!!

// 출력 결과 : 5

 

name 이라는 변수가 초기화되지 않은 상황에서,

해당 변수를 활용할 예정으로 늦은 초기화를 하는 상황이다.

 

name이 늦게 초기화 되었지만, textLength가 더 늦게 초기화되어서 위처럼 문제없이 사용할 수 있다.

 

 

 

✅ lazy 특징

 

● val 로만 선언할 수 있다.

늦은 초기화 이후, 값을 변경할 수 없다.

 

● 기존 원시 타입에도 사용할 수 있다.

 

● 메서드 내부에서도 사용할 수 있다.

 

● 타입을 명시하지 않아도 사용할 수 있다.

 

 

 


 

✅ 정리

 

● lateinit

- 늦은 초기화 이후에도 값을 변경해야 할 때 (var)

- 참조 타입만 적용할 수 있음

 

● lazy

- 늦은 초기화 이후에는 값이 불변할 때 (val)

- 원시 타입 대상으로 늦은 초기화를 적용해야 할 때

 

 

 


 

 

 

 

코틀린 늦은 초기화 기법에 대해 알아보았다.

각자 상황에 알맞게 사용하면 될 것 같다.