Intereting Posts

Kotlin – Инициализация имущества с использованием «ленивым» и «lateinit»

В Kotlin, если вы не хотите инициировать свойство класса внутри конструктора или в верхней части тела класса, у вас есть в основном эти два параметра (с помощью ссылки на язык):

  1. Ленивая инициализация

lazy () – это функция, которая принимает lambda и возвращает экземпляр Lazy, который может служить делегатом для реализации lazy-свойства: первый вызов get () выполняет lambda, переданный lazy (), и запоминает результат, последующие вызовы для получения () просто вернуть запоминаемый результат.

пример

public class Hello{ val myLazyString: String by lazy { "Hello" }` } 

Таким образом, первый вызов и подчиненные вызовы, где бы он ни находился , myLazyString вернут «Привет»,

  1. Поздняя инициализация

Обычно свойства, объявленные как имеющие ненулевой тип, должны быть инициализированы в конструкторе. Однако довольно часто это не удобно. Например, свойства могут быть инициализированы путем инъекции зависимостей или в методе установки единичного теста. В этом случае вы не можете предоставить инициализатор ненуля в конструкторе, но вы все же хотите избежать нулевых проверок при ссылке на свойство внутри тела класса.

Для обработки этого случая вы можете пометить свойство с помощью модификатора lateinit:

 public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() } } 

Модификатор может использоваться только для свойств var, объявленных внутри тела класса (не в основном конструкторе), и только тогда, когда свойство не имеет пользовательского getter или setter. Тип свойства должен быть непустым и не должен быть примитивным типом.

Итак, как правильно выбирать между этими двумя параметрами, поскольку обе они могут решить ту же проблему?

Solutions Collecting From Web of "Kotlin – Инициализация имущества с использованием «ленивым» и «lateinit»"

Вот существенные различия между lateinit var и by lazy { ... } делегированное свойство:

  • lazy { ... } делегат может использоваться только для свойств val , тогда как lateinit может применяться только к var s, потому что он не может быть скомпилирован в final поле, поэтому нельзя гарантировать неизменность;

  • lateinit var имеет поле поддержки, которое сохраняет значение, а by lazy { ... } создает объект-делегат, в котором значение хранится после вычисления, сохраняет ссылку на экземпляр делегата в объекте класса и генерирует getter для свойства который работает с экземпляром делегата. Поэтому, если вам нужно поле поддержки, присутствующее в классе, используйте lateinit ;

  • В дополнение к val s, lateinit не может использоваться для свойств с lateinit значением и примитивных типов Java (это из-за null используемого для неинициализированного значения);

  • lateinit var может быть инициализирован из любого места, где объект просматривается, например, изнутри кода структуры, и множественные сценарии инициализации возможны для разных объектов одного класса. by lazy { ... } , в свою очередь, определяет единственный инициализатор для свойства, который может быть изменен только путем переопределения свойства в подклассе. Если вы хотите, чтобы ваша собственность была инициализирована извне, возможно, неизвестно заранее, используйте lateinit .

  • Инициализация by lazy { ... } по умолчанию является потокобезопасной и гарантирует, что инициализатор вызывается не более одного раза (но это можно изменить, используя другую lazy перегрузку ). В случае lateinit var , код пользователя должен правильно инициализировать свойство в многопоточных средах.

  • Lazy экземпляр может быть сохранен, передан и даже использован для нескольких свойств. Напротив, lateinit var s не сохраняет никакого дополнительного состояния времени выполнения (только null в поле для неинициализированного значения).

  • Если вы держите ссылку на экземпляр Lazy , isInitialized() позволяет проверить, была ли она уже инициализирована (и вы можете получить такой экземпляр с отражением от делегированного свойства). Чтобы проверить, было ли свойство lateinit инициализировано, вы можете использовать property::isInitialized с Kotlin 1.2.

Кроме того, есть еще один способ, который не упоминается в вопросе: Delegates.notNull() , который подходит для отсроченной инициализации ненулевых свойств, в том числе для примитивных типов Java.

В дополнение к хорошему ответу на hotkey , вот как я выбираю среди этих двух на практике:

lateinit – для внешней инициализации: когда вам нужно внешнее вещество, чтобы инициализировать ваше значение, вызывая метод.

например, позвонив:

 private lateinit var value: MyClass fun init(externalProperties: Any) { value = somethingThatDependsOn(externalProperties) } 

В то время как lazy – это когда он использует только внутренние зависимости от вашего объекта.

Кредит отправляется @Amit Shekhar

lateinit

lateinit – это поздняя инициализация.

Обычно свойства, объявленные как имеющие ненулевой тип, должны быть инициализированы в конструкторе. Однако довольно часто это не удобно. Например, свойства могут быть инициализированы путем инъекции зависимостей или в методе установки единичного теста. В этом случае вы не можете предоставить инициализатор ненуля в конструкторе, но вы все же хотите избежать нулевых проверок при ссылке на свойство внутри тела класса.

Пример:

 public class Test { lateinit var mock: Mock @SetUp fun setup() { mock = Mock() } @Test fun test() { mock.do() } } 

ленивый

ленивый – ленивая инициализация.

lazy () – это функция, которая принимает лямбда и возвращает экземпляр lazy, который может служить делегатом для реализации свойства lazy: первый вызов get () выполняет лямбду, переданную в lazy (), и запоминает результат, последующие вызовы для получения () просто вернуть запоминаемый результат.

Пример:

 public class Example{ val name: String by lazy { “Amit Shekhar” } } 

Если вы используете Spring-контейнер, и вы хотите инициализировать поле, lateinit , lateinit лучше подходит.

 @Autowired lateinit var MyBean myBean 

Очень короткий и сжатый ответ

lateinit: он инициализирует ненулевые свойства в последнее время

В отличие от ленивой инициализации, lateinit позволяет компилятору распознавать, что значение свойства non-null не сохраняется на этапе конструктора для компиляции в обычном режиме.

ленивая инициализация

по лени, может быть очень полезно при реализации свойств только для чтения (val), которые выполняют ленивую инициализацию в Котлине.

lazy {…} выполняет свой инициализатор, в котором сначала используется определенное свойство, а не его объявление.