Привет, когда я использую 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 является исключением во время выполнения.