Kotlin lateinit корреспондент java

Привет, когда я использую Kotlin для программирования Android, я видел в коде код lateinit . Что такое эквивалент в java? Как я могу изменить этот код с Kotlin на Java?

 public class MyTest { lateinit var subject: TestSubject } 

lateinit в Kotlin существует, так что вы можете иметь типы с lateinit значением для переменных, которые вы не можете инициализировать в момент создания класса, содержащего их.

Используя ваш пример, если вы не использовали lateinit , вам нужно сделать subject нулевым, так как он должен быть инициализирован значением.

 public class MyTest { var subject: TestSubject? = null } 

Это заставит вас делать нулевые проверки каждый раз, когда вы его используете, что является уродливым, поэтому вы можете пометить его как lateinit вместо этого.


В Java у вас действительно нет этой проблемы, так как все имеет значение NULL, и объявление неинициализированного поля ничего особенного:

 public class JavaTest { TestSubject subject; } 

Это инициализируется с null , поэтому он практически эквивалентен не- lateinit примеру Котлина.

Единственное реальное различие между версией lateinit в Kotlin и версией Java заключается в том, что вы получаете более конкретное исключение при попытке получить доступ к неинициализированному свойству в Kotlin, а именно UninitializedPropertyAccessException , что упростит его отладку, нежели искать причину общего NullPointerException .


Если вы действительно хотели это немного другое поведение, вы можете обернуть ваши свойства Java в каких-то оболочках, но я не думаю, что это стоило бы синтаксических накладных расходов. Очень простой способ (например, небезопасный, например) способ сделать это:

У вас есть общий класс-оболочка для свойств:

 public class Property<T> { private T value = null; public T get() { if (value == null) throw new UninitializedPropertyAccessException("Property has not been initialized"); return value; } public void set(T value) { if (value == null) throw new IllegalArgumentException("Value can't be null"); this.value = value; } } 

Используйте эту оболочку в своих классах:

 public class JavaTest { Property<TestSubject> subject = new Property<>(); } 

И тогда это использование даст вам неинициализированное исключение:

 JavaTest test = new JavaTest(); test.subject.get(); 

И это будет нормально:

 JavaTest test = new JavaTest(); test.subject.set(new TestSubject()); test.subject.get(); 

Редактировать: это очень похоже на то, как lateinit работает в Kotlin, если вы декомпилируете байт-код вашего примера на Java, это то, что вы получаете:

 public final class MyTest { @NotNull public TestSubject subject; @NotNull public final TestSubject getSubject() { TestSubject var10000 = this.subject; if(this.subject == null) { Intrinsics.throwUninitializedPropertyAccessException("subject"); } return var10000; } public final void setSubject(@NotNull TestSubject var1) { Intrinsics.checkParameterIsNotNull(var1, "<set-?>"); this.subject = var1; } } 

В основном, компилятор помещает код для проверки доступа к свойствам внутри самого класса (+ использует некоторые вспомогательные методы) вместо использования обертки, что является более эффективным.

На Java нет такого свойства, которое задерживает инициализацию свойства. Но я думаю, что поведение в Котлине и Яве очень похоже.

Вот мои два цента:

В Kotlin доступ к свойства lateinit до его инициализации вызывает особое исключение, которое четко идентифицирует доступное свойство и тот факт, что он не был инициализирован. (Ссылка: https://kotlinlang.org/docs/reference/properties.html ).

В Java также вызывается NullPointerException (NPE), указывающее, что доступ к ресурсу – Null.

Единственное различие может заключаться в том, что NPE является исключением во время выполнения.