Uing? Uing!!

[내 맘대로 정리한 Kotlin] lateinit과 by lazy의 차이점 본문

Kotlin

[내 맘대로 정리한 Kotlin] lateinit과 by lazy의 차이점

Uing!! 2020. 9. 30. 15:57
반응형

늦은 초기화

가끔 클래스 안에서 '내가 이 변수를 쓸 것이다'라고 선언만 해 놓고,

나중에 값을 사용할 수 있게 되면 그 때 값을 입력해 주고 싶을 때가 있다.

이럴 때 사용 가능한 방법 중에는 아래와 같이 일단 null로 설정해 준 뒤 나중에 바꾸는 방법이 있기는 하다.

var x : String? = null

하지만 두 가지, 마음에 걸리는 상황이 생길 수 있다.

 

1) x의 값이 변할 수는 있지만, 절대 null이어서는 안 되는 경우 -> 처음에 nullable한 <String?>으로 초기화해주는 것이 부적절함

2) x의 값이 처음 한 번만 정해지면 다시는 변하지 않는 경우 -> x가 var일 이유가 없음

 

애초에 '나중에 쓸 것'이라는 걸 알고 있는데, '왜 처음에 null로 고정을 해 주어야 하냐?' 라는 문제다.

이럴 때를 위해 제공되는 문법이 lateinit, 그리고 by lazy이다.

lateinit

lateinit은 이렇게 사용된다.

lateinit var x : String
x = "Initialized"
println(x)

처음에 var 형태의 x가 나중에 사용될 것이며, String 타입이라는 것만 정해 준다.

그리고 이후에 사용할 때에 값을 지정해 주면 x에 값이 들어간다.

 

이 lateinit을 처음 제시된 방법과 비교했을 때, 가장 큰 차이점은 x가 String? 타입이 아닌 String 타입이라는 점이다.

x가 null이 될 수 없기 때문에, 이후에 x = null와 같이 선언해 주면 에러가 발생한다.

 

또한 x에 값이 들어가기 전에 x는 null이 아니라 uninitialized(초기화되지 않음) 상태로 존재한다.

이 상태에서 x를 바로 사용하려고 한다면 초기화되지 않았다는 에러가 발생하게 된다.

따라서 lateinit으로 변수를 선언해 주었다면 사용 전에 꼭 초기화 단계를 거쳐야 한다.

 

* 단, lateinit의 경우에는 Int, Long, Double, Float와 같은 Primitive Type에 대해서는 사용할 수 없다.

 

by lazy

by lazy는 이렇게 사용된다.

val x : String by lazy { "Initialized!" }
println(x)

처음에 val 형태의 x가 나중에 사용될 것이며, '사용 시에' 어떤 값이 들어가는지를 정해 준다.

이후에 따로 지정할 필요는 없고, 두 번째 줄과 같이 x를 사용하는 첫 순간에 x에 값이 들어간다.

 

이 코드에서는 사실 by lazy가 필요하지는 않다. 초기화될 값이 정해져 있기 때문이다.

하지만 만약 x가 다른 계산식의 영향을 받거나, 다른 변수의 초기화 이후에만 값을 알 수 있다면 이 방식을 사용할 수 있다.

 

이를테면 이런 상황이다.

lateinit var inputValue : String
val x : Int by lazy { inputValue.length }
inputValue = "Initialized!"
println(x)

이 코드의 경우, x는 inputValue라는 문자열의 길이를 받아와야 한다.

그런데 inputValue는 lateinit으로 설정되어 있기 때문에, 아직 그 길이를 알 수가 없다.

 

무조건 inputValue가 제대로 값을 가지게 된 후에 x를 활용할 예정이라면, 이 때 이용할 수 있는 문법이 by lazy다.

x는 변수가 '처음 사용되는 순간'인 4번째 줄의 출력문에서 inputValue.length로 초기화된다.

 

x를 사용하기 전에 inputValue 친구만 초기화를 해 주었다면,

어디에서 호출하든 특별히 추가적인 선언문을 작성할 필요가 없는 것이다.

 

lateinit vs by lazy

위에서 살펴보았듯이 lateinit과 by lazy는 유사한 점이 많다.

특히 값을 나중에 초기화한다는 기본적인 목적은 같다고 볼 수 있다.

 

하지만 두 문법의 특성과 각각을 사용하는 상황에는 몇 가지 차이점이 있고,

그중 가장 큰 차이점은 lateinit은 var로만, by lazy는 val로만 선언된다는 점이다.

 

이렇기 때문에 초기화 이후에 값이 변할 수 있는 변수에는 lateinit을,

처음 초기화 된 직후부터 계속 read-only로만 쓰이는 변수에는 by lazy를 사용하는 것이 좋다.

반응형
Comments