74 votes

Kotlin: Vérifiez si la valeur paresseuse a été initialisée

Est-il un moyen de savoir si un paresseux val a été initialisé dans Kotlin sans initialiser dans le processus?

par exemple si j'ai un paresseux val, se demandant si elle est null instancier

val messageBroker: MessageBroker by lazy { MessageBroker() }
if (messageBroker == null) {
    // oops
}

Je pourrais éventuellement utiliser une deuxième variable, mais qui semble en désordre.

private var isMessageBrokerInstantiated: Boolean = false
val messageBroker: MessageBroker by lazy {
    isMessageBrokerInstantiated = true
    MessageBroker()
}

...

if (!isMessageBrokerInstantiated) {
    // use case
}

Est-il une manière sexy de la détermination de cette, comme if (Lazy(messageBroker).isInstantiated())?

Liée (mais pas le même): Comment faire pour vérifier si un "lateinit" variable a été initialisée?

107voto

voddan Points 16

Il existe un moyen, mais vous devez accéder à l'objet délégué qui est renvoyé par lazy {} :

 val messageBrokerDelegate = lazy { MessageBroker() }
val messageBroker by messageBrokerDelegate

if(messageBrokerDelegate.isInitialized())
    ...
 

isInitialized est une méthode publique sur l'interface Lazy<T> , voici la documentation .

36voto

hotkey Points 119

Depuis Kotlin 1.1, vous pouvez accéder à une propriété délégué directement à l'aide d' .getDelegate().

Vous pouvez écrire une extension de la propriété d'un bien de référence qui vérifie qu'il a un Lazy délégué qui a déjà été initialisé:

/**
 * Returns true if a lazy property reference has been initialized, or if the property is not lazy.
 */
val KProperty0<*>.isLazyInitialized: Boolean
    get() {
        if (this !is Lazy<*>) return true

        // Prevent IllegalAccessException from JVM access check on private properties.
        val originalAccessLevel = isAccessible
        isAccessible = true
        val isLazyInitialized = (getDelegate() as Lazy<*>).isInitialized()
        // Reset access level.
        isAccessible = originalAccessLevel
        return isLazyInitialized
    }

Puis, à l'utilisation du site:

val messageBroker: MessageBroker by lazy { MessageBroker() }

if (this::messageBroker.isLazyInitialized) {
    // ... do stuff here
}

Cette solution exige kotlin-reflect à être dans le classpath. Avec Gradle, l'utilisation
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

L' isAccessible = true part n'est requise pour l' .getDelegate(), parce que sinon il ne peut pas accéder au domaine privé de stocker le délégué de référence.

19voto

Stephen Talley Points 327

En s'appuyant sur la solution de raccourci clavier , vous pouvez créer une propriété isLazyInitialized (au lieu d'une fonction), pour être cohérent avec la propriété isInitialized pour les vars Lateinit.

De plus, il n'est pas nécessaire de gérer le cas nul.

 import kotlin.reflect.KProperty0,
import kotlin.reflect.jvm.isAccessible

val KProperty0<*>.isLazyInitialized: Boolean
    get() {
        // Prevent IllegalAccessException from JVM access check
        isAccessible = true
        return (getDelegate() as Lazy<*>).isInitialized()
    }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X