Kotlin by lazy vs lateinit

Kotlin – Property initialization using «by lazy» vs. «lateinit»

Kotlin library provides two different access modifiers for property declaration.

In this article, we will highlight the difference between these two access modifiers and how we can use them in our application.

Lateinit

In order to create a «lateInit» variable, we just need to add the keyword «lateInit» as an access modifier of that variable. Following are a set of conditions that need to be followed in order to use «lateInit» in Kotlin.

  • Use «lateInit» with a mutable variable. That means, we need to use «var» keyword with «lateInit».
  • «lateInit» is allowed only with non-NULLable data types.
  • «lateInit» does not work with primitive data types.
  • «lateInit» can be used when the variable property does not have any getter and setter methods.

Example

We will be declaring a variable as lateInit and we will see how we can access the same throughout the program.

class Tutorial < lateinit var name : String fun checkLateInit()< // checking whether the value is assigned or not if(this::name.isInitialized) println("Your value is not assigned"); else< // initializing name name = "www.tutorialspoint.com/" println(this.name) // this will return true >> > fun main()

Читайте также:  Supermicro ipmi java problem

Output

Once you execute the code, it will generate the following output −

Lazy Initialization

For efficient memory management, Kotlin has introduced a new feature called as Lazy initialization. When the lazy keyword is used, the object will be created only when it is called, otherwise there will be no object creation. lazy() is a function that takes a lambda and returns an instance of lazy which can serve as a delegate of lazy properties upon which it has been applied. It has been designed to prevent unnecessary initialization of objects.

  • Lazy can be used only with non-NULLable variables.
  • Variable can only be val. «var» is not allowed .
  • Object will be initialized only once. Thereafter, you receive the value from the cache memory.
  • The object will not be initialized until it has been used in the application.

Example

In this example, we will declare a lazy variable «myName» and we could see that the call to this parts of the code will happen only once and when the value is initialized, it will remember the value throughout the application. Once the value is assigned using lazy initialization, it cannot be reassigned .

Output

Once you execute the code, it will generate the following output −

Welcome to Lazy declaration www.tutorialspoint.com Second time call to the same object--www.tutorialspoint.com

Источник

lateinit vs lazy Property in Kotlin

Since object creation is a heavy process as it initialises all the public and private properties defined in that class when the constructor is called, Kotlin has few ways to initialise properties later when required. We already discussed lateinit properties and lazy properties. Let’s try to understand some basic differences between then and when to use what. But before that let’s quickly recap the lateinit and lazy properties

lateinit property

lateinit properties are the var properties that can be initialised later in the constructor or in any function according to the use.


data class User (val id : Long,
val username : String) : Serializable

lateinit var lateinitUser : User

lazy property

lazy properties are the val properties that can also be initialised later when they are called the first time.


val lazyUser : User? by lazy User(id = 1, username = "agrawalsuneet")
>

Now lets try to understand difference between them.

lateinit var whereas lazy val

lateinit can only be used with a var property whereas lazy will always be used with val property. A lateinit property can be reinitialised again and again as per the use whereas the lazy property can only be initialised once.


lateinit var lateinitUser : User

val lazyUser : User? by lazy User(id = 1, username = "agrawalsuneet")
>

lateinit can’t have custom getter or setter whereas lazy has custom getter

A lateinit property can’t have a custom getter whereas a lazy property has a block that gets executed whenever the first time that property is called.


val lazyUser : User by lazy //can do other initialisation here
User(id = 1, username = "agrawalsuneet")
>

isInitialized

In order to check if a lateinit property is initialised or not, we can use the extension function to KProperty directly which returns a boolean if the property is initialised or not.


/**
* Returns `true` if this lateinit property has been assigned a value, and `false` otherwise.
*
* Cannot be used in an inline function, to avoid binary compatibility issues.
*/
@SinceKotlin("1.2")
@InlineOnly
inline val @receiver:AccessibleLateinitPropertyLiteral KProperty0.isInitialized: Boolean
get() = throw NotImplementedError("Implementation is intrinsic")

println(::lateinitUser.isInitialized)

Since the lazy block returns an object which implements the Lazy interface, we can check if the variable is initialised or not in the case of the lazy property also but for that, we need to split the lazy call.


val lazyUserDelegate = lazy < User(id = 1, username = "agrawalsuneet") >
val lazyUser by lazyUserDelegate

println(lazyUserDelegate.isInitialized())

Primitive types

lateinit properties can’t be of primitive data types whereas lazy properties can be of primitive date types also.


lateinit var lateinitInt : Int //compilation error: 'lateinit' modifier is not allowed on properties of primitive types

val lazyInt by lazy 10
>

Thread Safety

We can’t define the thready safety in case of lateinit property but in case of lazy, we can choose between SYNCHRONIZED , PUBLICATION and NONE .


val lazyUser : User? by lazy(LazyThreadSafetyMode.SYNCHRONIZED) User(id = 1, username = "agrawalsuneet")
>

Nullable Type


lateinit var lateinitUser : User? //compilation error: 'lateinit' modifier is not allowed on properties of nullable types

val lazyUser : User? by lazy User(id = 1, username = "agrawalsuneet")
>

Accessing before initialisation

Accessing a lateinit property before it has been initialized throws a special exception that clearly identifies the property being accessed and the fact that it hasn’t been initialized. We can’t ever access a lazy property before it hased been initialised. Remember that the lazy property can be null but the initialisation will still happen when the first time the property will be called. Based on the above difference we can decide when to use the lateinit property or when to use the lazy property. The developer doesn’t have to remember if the property is initialised or not in case of lazy property but in case of lateinit we need to remember the flow. There are no guidelines in order to decide when to use what but according to the use case, we can decide.

Источник

Отложенная инициализация(by lazy, lateinit)

Ключевое слово by lazy служит для отложенной инициализации через механизм делегатов. Делегат lazy принимает лямбда-выражение с кодом, который вы бы хотели выполнить для инициализации свойства.

Иногда требуется объявить переменную, но отложить инициализацию. Причины задержки инициализации могут быть самыми разными. Например, для инициализации требуются предварительные вычисления, которые желательно не выполнять, если их результат никогда не будет использован. Обычно в таких случаях переменную объявляют через var, которая получает значение null, пока не будет инициализирована нужным значением, которое потом никогда не меняется.

 var catName: String? = null . catName = getName() // присваиваем значение 

Это неудобно, если вы знаете, что у переменной будет конкретное значение и вы хотите избегать значения null. В нашем примере переменная имеет тип String?, который поддерживает значение null, хотя могла бы иметь тип String. Как вариант, можно было использовать заданное значение, например:

 var catName: String = "NOT_INITIALIZED" // или пустая строка var catName: String = "" . catName = getValue() 

В любом случае приходится использовать var, даже зная, что после инициализации значение переменной никогда не изменится. Kotlin предлагает для подобных случаев использовать by lazy:

 val catName: String by lazy

В этом случае функция getName() будет вызвана только один раз, при первом обращении к catName. Вместо лямбда-выражения можно также использовать ссылку на функцию:

 val catName: String by lazy(::getName) 
 val infoTextView by lazy < view. findViewById(R.id.textView) > 

Модификатор lateinit

Иногда переменную нельзя сразу инициализировать, сделать это можно чуть позже. Для таких случаев придумали новый модификатор lateinit (отложенная инициализация). Это относится только к изменяемым переменным.

 private lateinit var button: Button 

Переменная обязательно должна быть изменяемой (var). Не должна относиться к примитивным типам (Int, Double, Float и т.д). Не должна иметь собственных геттеров/сеттеров.

Подобный подход удобен во многих случаях, избегая проверки на null. В противном случае пришлось бы постоянно использовать проверку или утверждение !!, что засоряет код.

Если вы обратитесь к переменной до её инициализации, то получите исключение «lateinit property . hos not been initialized» вместо NullPointerException.

В любое объявление var-свойства можно добавить ключевое слово lateinit. Тогда Kotlin позволит отложить инициализацию свойства до того момента, когда такая возможность появится. Это полезная возможность, но её следует применять осторожно. Если переменная с поздней инициализацией получит начальное значение до первого обращения к ней, проблем не будет. Но если сослаться на такое свойство до его инициализации, то получим исключение UninitializedPropertyAccessException. Как вариант, можно использовать тип с поддержкой null, но тогда придётся обрабатывать возможное значение null по всему коду. Получив начальное значение, переменные с поздней инициализацией будут работать так же, как другие переменные.

Для проверки факта инициализации переменной вызывайте метод isInitialized(). Функцию следует использовать экономно — не следует добавлять эту проверку к каждой переменной с поздней инициализацией. Если вы используете isInitialized() слишком часто, то скорее всего вам лучше использовать тип с поддержкой null.

 lateinit var catName: String override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) catName = "Barsik" if (::catName.isInitialized) < Log.d("Kot", "Hi, $catName") >> 

Источник

Оцените статью