Як перевірити, чи була ініціалізована змінна "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?) і просто перевірити, чи не замість неї нульове значення?
Marcin Koziński

1
Ну, я насправді спробував це, і це зробить трюк, проте мені доведеться відредагувати allSeriesvar seriesDir?.listFiles()?.map { it.name }?.toTypedArray(), який не дуже "гарний"
Mathew Hany

1
Ви можете зробити звичайну стару нульову перевірку, а розумний склад зробить її красивішою. if (seriesDir != null) { allSeries = seriesDir.listFiles().map { it.name }.toTypedArray() }
Marcin Koziński

Просимо прийняти більш актуальну відповідь
мізантроп

Відповіді:


977

Існує lateinitполіпшення в Kotlin 1.2, що дозволяє перевірити стан ініціалізації lateinitзмінної безпосередньо:

lateinit var file: File    

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

Дивіться повідомлення в блозі JetBrains або пропозицію KEEP .

ОНОВЛЕННЯ: Kotlin 1.2 випущений. Ви можете знайти lateinitвдосконалення тут:


3
@ fer.marino: Ну, Kotlin 1.2 фактично дозволяє використовувати lateinitтакож і для локальних змінних, див. kotlinlang.org/docs/reference/…
xsveda

9
this :: lateinitVar.isInitialized
vihkat

17
що означає ::раніше file?
Malwinder Singh

5
@MalwinderSingh створює посилання на члена або довідник про клас.
notGeek

5
Зараз закоханий у котлін
Naveed Ahmad

46

Використовуючи .isInitializedвластивість, можна перевірити стан ініціалізації змінної lateinit.

if(::file.isInitialized){
    //File is initialized
}else{
    //File is not initialized
}

Це не дає відповіді на запитання. Щоб критикувати або вимагати роз'яснення у автора, залиште коментар під їх дописом. - З огляду
gforce301

2
@ gforce301 Це безумовно буде використано для перевірки.
Нікхіл Катехайе

39

Спробуйте використовувати його, і ви отримаєте, UninitializedPropertyAccessExceptionякщо воно не буде ініціалізовано.

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

EDIT: Виходячи з того, що ви хочете зробити щось подібне, буде працювати краще:

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

// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())

У мене є програма JavaFX, і у мене є кнопка, яка завжди буде відключена, якщо lateinitне буде ініціалізована змінна (яка є ). Іншими словами: я хочу, щоб кнопку було відключено до тих пір, поки змінна не була ініціалізована. Чи є хороший спосіб це зробити?
Меттью Гані

@MathewHany Як би це було ініціалізовано нормально? Можливо, ви захочете подивитися на власників / налаштувачів властивостей та на SimpleBooleanProperty, які можна прив’язати до вимкненої властивості кнопки
Kiskae

1
Щоб бути більш конкретним, у мене є проста програма, яка містить 4 кнопки, перша кнопка відкриє діалогове вікно DirectoryChooser, а інші 3 будуть відключені, коли користувач вибере каталог, тоді всі інші кнопки будуть доступні користувачеві.
Mathew Hany

@MathewHany ви можете реально реалізувати це, використовуючи SimpleObjectProperty, щоб утримувати вибраний файл, а потім за допомогою isNullприв'язки відключити інші кнопки.
Kiskae

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клас. І ми отримуємо поле резервного резервування помилок у цьому пункті недоступне. Перевірте вже поставлене питання з цього приводу.


12

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

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}

Я використовую локальну змінну init, коли я використовую цю перевірку, яка дає помилку на зразок невирішеної посилання
MarGin

3

Щоб перевірити, чи lateinit varбуло ініціалізовано a , чи не використовувати а .isInitializedна посилання на цю властивість:

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

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


1
що означає ::раніше bar?
Malwinder Singh

@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 тоді кидає 'кинутиUninitializedPropertyAccessException', ще повернути локальний об'єкт. Вище пояснюваний байт-код пояснюється тут Рішення Оскільки kotlin 1.2 дозволяє перевіряти погоду lateinit var був ініціалізований або не використовується.isInitialized

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.