Как проверить, была ли инициализирована переменная lateinit?

428

Интересно, есть ли способ проверить, была ли lateinitпеременная инициализирована? Например:

class Foo() {

    private lateinit var myFile: File

    fun bar(path: String?) {
        path?.let { myFile = File(it) }
    }

    fun bar2() {
        myFile.whateverMethod()
        // May crash since I don't know whether myFile has been initialized
    }
}
Мэтью Хани
источник
3
Может быть, вам нужно сделать свойство обнуляемым (изменить тип на File?) и просто проверить, является ли оно пустым?
Марцин Козиньски
1
Ну, на самом деле я попробовал это, и это сработает, но мне придется редактировать allSeriesvar seriesDir?.listFiles()?.map { it.name }?.toTypedArray(), что не очень "красиво"
Мэтью Хани
1
Вы можете сделать простую старую проверку на нулевое значение, и умное приведение сделает его красивее. if (seriesDir != null) { allSeries = seriesDir.listFiles().map { it.name }.toTypedArray() }
Марцин Козиньски
Пожалуйста, подумайте о принятии более актуального ответа
мизантроп

Ответы:

979

Eсть lateinit Kotlin 1.2 улучшение, позволяющее lateinitнапрямую проверять состояние инициализации переменной:

lateinit var file: File    

if (this::file.isInitialized) { ... }

Смотрите анонс на блоге JetBrains или предложение KEEP .

ОБНОВИТЬ: Kotlin 1.2 был выпущен. Вы можете найти lateinitулучшения здесь:

xsveda
источник
3
@ fer.marino: Ну, на самом деле Котлин 1,2 позволяет использовать lateinitтакже для локальных переменных см kotlinlang.org/docs/reference/...
xsveda
9
this :: lateinitVar.isInitialized
vihkat
17
что значит ::раньше file?
Малвиндер Сингх,
5
@MalwinderSingh создает ссылку на член или ссылку на класс.
NotGeek
5
Сейчас влюблен в котлина
Навид Ахмад
46

Используя .isInitializedсвойство можно проверить состояние инициализации переменной lateinit.

if(::file.isInitialized){
    //File is initialized
}else{
    //File is not initialized
}
Нихил Катехай
источник
Это не дает ответа на вопрос. Чтобы критиковать или запросить разъяснения у автора, оставьте комментарий под своим постом. - Из обзора
gforce301
2
@ gforce301 Это определенно будет использоваться для проверки.
Нихил Катехай
39

Попробуйте использовать его, и вы получите, UninitializedPropertyAccessExceptionесли он не инициализирован.

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

РЕДАКТИРОВАТЬ: Исходя из того, что вы хотите сделать, что-то вроде этого будет работать лучше:

val chosenFile = SimpleObjectProperty<File?>
val button: Button

// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())
Kiskae
источник
У меня есть приложение JavaFX, и у меня есть кнопка, которая всегда будет отключена, если lateinitне была инициализирована переменная (которая есть ). Другими словами: я хочу, чтобы кнопка была отключена, пока переменная не была инициализирована. Есть ли хороший способ сделать это?
Мэтью Хани
@MathewHany Как это будет нормально инициализироваться? Возможно, вы захотите взглянуть на свойства getter / setters и SimpleBooleanProperty, которые вы можете привязать к отключенному свойству кнопки
Kiskae
1
Чтобы быть более конкретным, у меня есть простое приложение, которое содержит 4 кнопки, первая кнопка откроет диалоговое окно DirectoryChooser, а остальные 3 будут отключены, когда пользователь выбирает каталог, тогда все остальные кнопки будут доступны пользователю.
Мэтью Хани
@ MathewHany Вы можете реализовать это с помощью SimpleObjectProperty для хранения выбранного файла, а затем с помощью isNullпривязки для отключения других кнопок.
кискае
1
kotlinlang.org/docs/reference/… xsveda ответ более актуален
Серж
19

Вы можете легко сделать это:

::variableName.isInitialized

или

this::variableName.isInitialized

Но если вы находитесь внутри слушателя или внутреннего класса, сделайте это:

this@YourClassName::variableName.isInitialized

Примечание. Вышеприведенные операторы работают нормально, если вы пишете их в том же файле (тот же класс или внутренний класс), где объявлена ​​переменная, но это не будет работать, если вы хотите проверить переменную другого класса (не суперкласса или объявленного в другой файл) , например:

class Test {
    lateinit var str:String
}

И проверить, инициализирована ли str:

введите описание изображения здесь

То , что мы делаем здесь доступа поле strиз Testкласса в Test2класс. И мы получаем сообщение о том, что резервное поле var не доступно на этом этапе. Проверьте уже заданный вопрос по этому поводу.

Сурадж Вайшнав
источник
12

Принятый ответ дает мне ошибку компилятора Kotlin 1.3+, я должен был явно упомянуть thisключевое слово раньше ::. Ниже приведен рабочий код.

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}
Саззад Хисейн Хан
источник
Я использую локальную переменную init, когда использую эту проверку, которая выдает ошибку, такую ​​как неразрешенная ссылка
MarGin
3

Чтобы проверить, lateinit varбыли ли инициализированы или не использовать.isInitialized ссылку на это свойство:

if (foo::bar.isInitialized) {
    println(foo.bar)
}

Эта проверка доступна только для свойств, которые доступны лексически, то есть объявлены в том же типе или в одном из внешних типов, или на верхнем уровне в том же файле.

Энди
источник
1
что значит ::раньше bar?
Малвиндер Сингх,
@Malwinder Singh "создает ссылку на член или ссылку на класс" - Kotlin Doc
DMonkey
0
kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized

Байт-код говорит ... бла-бла ..

public final static synthetic access$getClientKeypair$p(Lcom/takharsh/ecdh/MainActivity;)Ljava/security/KeyPair;

`L0
LINENUMBER 11 L0
ALOAD 0
GETFIELD com/takharsh/ecdh/MainActivity.clientKeypair : Ljava/security/KeyPair;
DUP
IFNONNULL L1
LDC "clientKeypair"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwUninitializedPropertyAccessException (Ljava/lang/String;)V
    L1
ARETURN

L2 LOCALVARIABLE $ this Lcom / takharsh / ecdh / MainActivity; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1

Kotlin создает дополнительную локальную переменную того же экземпляра и проверяет, имеет ли она значение NULL или нет, если NULL, то генерирует исключение throwUninitializedPropertyAccessException, иначе возвращает локальный объект. Над байткод объяснен здесь решение Поскольку Котлин 1.2 позволяет проверить погоду lateinit вар инициализирован или не используется.isInitialized

takharsh
источник