[Sécurité Null] Mémo de comparaison Kotlin Java Utilisation correcte de la sécurité Null

Quel article?

Comment écrivez-vous quelque chose comme ça en Java dans Kotlin? Un mémorandum de comparaison de code.

[Kotlin] [Java] Mémo de comparaison Kotlin Java Cet article est spécialisé dans la partie fonction de sécurité Null de.

Je veux connaître les bases de Kotlin en le comparant à Java! Veuillez consulter l'article ci-dessus pour ceux qui le disent.

Public cible

Qu'est-ce que la sécurité nulle?

Il fait référence à un mécanisme qui n'autorise pas Null en principe.

Par exemple, le code suivant

test.kt


val a: String = null

Cela entraînera une erreur de compilation. C'est parce que Kotlin n'autorise pas les valeurs nulles par défaut. Si vous souhaitez autoriser null, ajoutez? Après le type.

test.kt


val a: String? = null //C'est acceptable

Une vérification nulle est toujours requise lors de l'accès à une variable définie avec une option. Comparons-le avec Java.

test.java


String a = null;
a.contains("hoge"); //Naturellement c'est nul, donc ça tombe avec nullpo

test.kt


var a: String? = null
a.contains("hoge") //Il ne compile pas en premier lieu

Cette source de Kotlin est lue au moment de la compilation. C'est parce que non-null n'est pas garanti. Pour accéder aux types Nullable:

test.kt


val a: String? = null
a?.contains("hoge")

Pour les appels de fonction de type Nullable, faites quelque chose comme?. Si a est Null, contient ne sera pas exécuté et Null sera retourné.

Quand j'essaye d'y parvenir avec Java,

Tout d'abord, la vérification Null familière.

test.java


String a = null;

if (a != null) {
    a.contains("hoge"); //S'il est nul, il ne passera pas ici
}

Avec Java 8, vous pouvez utiliser la fonction équivalente appelée facultative.

test.java


Optional<String> a = Optional.of(null);
a.ifPresent(notNull -> notNull.contains("hoge")) //contient est exécuté uniquement lorsque le contenu de a n'est pas nul

Vous pouvez voir qu'il peut être écrit de manière très concise par rapport à Java Java n'est qu'une vérification à l'exécution, donc même si vous utilisez Java 8 Facultatif En premier lieu, ce n'est pas une solution fondamentale lorsque vous oubliez d'utiliser Optional. Kotlin est vérifié au moment de la compilation, donc la vérification Null ne sera pas manquée.

Valeur renvoyée lors de l'appel d'une méthode Java

Mais les fonctions de sécurité Null de Kotlin ne sont pas non plus parfaites. Par exemple, lors de l'appel d'une méthode Java à partir de Kotlin comme suit

test.kt


var str = System.getProperty("hoge") //str est une chaîne!Moule

Étant donné que Java n'a pas de fonction de sécurité nulle, il est affecté de force en tant que type non nul du côté Kotlin. Si vous forcez une valeur Java à être non nulle, un! Sera ajouté après le type.

C'est un peu délicat et se comporte comme non nul, mais cela pourrait être nul.

test.kt


var str = System.getProperty("hoge")
var strLength = str.length //Parce que ce n'est pas un type Nullable?.Je n'ai pas besoin

Mais bien sûr, getProperty (" hoge ") peut être retourné comme null, donc strLength peut tomber gluant. Cela ne signifie pas que la sécurité nulle absolue a été garantie.

Si vous le déclarez explicitement comme type Nullable lors de la réception de la valeur de retour de la méthode Java, il sera de type Nullable.

test.kt


var str: String? = System.getProperty("hoge")
var strLength = str?.length //Parce que c'est un type Nullable?.Est nécessaire

Il est très difficile de gérer cela. .. Si vous souhaitez supprimer complètement Null, vous devez explicitement le rendre Nullable.

Déballage nul

Regardons à nouveau l'exemple précédent

test.kt


var str: String? = System.getProperty("hoge")
var strLength = str?.length

Dans ce cas, le type de la variable str est String?, Donc la strLength à laquelle la valeur de la longueur de str est affectée est ʻInt? `. En d'autres termes, si le type de la source d'affectation est Nullable, la variable de la destination de l'affectation sera également Nullable. Avec cela, seules les variables censées être Nullables sont créées et les avantages de la fonction de sécurité Null ne peuvent pas être pleinement exploités.

Si vous souhaitez rendre le type qui était autrefois nullable non nul, il existe les deux méthodes suivantes

Déballage forcé

test.kt


var str: String? = System.getProperty("hoge")
var foo = str!!.length // !!Vous pouvez forcer str à être de type String en
//foo devient de type Int

Si le type qui est devenu Nullable une fois est !! ,? Sera supprimé.

test.kt


var str: String? = System.getProperty("hoge")
str = str!! //str devient un type String
var foo = str.length // non-Parce que c'est nul?.Ou!!.Aucun opérateur nécessaire

Naturellement, si str est nul, il tombera avec un po gluant. Il est inutile d'en faire un type Nullable.

Développer à l'aide de l'opérateur Elvis

test.kt


var str = System.getProperty("hoge") ?: "Unknown Property"
var foo = str.length //str devient un type String

Ceci ?: Est appelé l'opérateur Elvis et évalue l'expression de droite lorsque le résultat de l'expression de gauche de?: Est Null.

test.java


String str = System.getProperty("hoge") != null ? System.getProperty("hoge") : "Unknown Property";

Synonyme de.

Même si Systrem.getProperty ("hoge") est Null, une valeur dédiée est renvoyée à ce moment-là, donc str devient String type et foo devient ʻInt type`. Le type Nullable a disparu et vous pouvez désormais gérer les variables en toute sécurité.

Si vous ne souhaitez pas renvoyer une valeur dédiée, c'est-à-dire si elle est Null, vous ne souhaitez pas continuer le traitement suivant.

test.kt


var str = System.getProperty("hoge") ?: return //str devient un type String

Ensuite, si System.getProperty (" hoge ") est Null, vous pouvez quitter le traitement de ce bloc.

Histoire pratique

test.kt


var str = System.getProperty("hoge") ?: return //str devient un type String

En déballant comme ça, il ne tombe plus avec du gluant, Cependant, il n'est pas possible de détecter une erreur simplement en retournant et en quittant le processus sans échouer. En premier lieu, ce code doit supposer que System.getProperty ("hoge") n'obtient pas null.

Si vous souhaitez détecter des retours inattendus sans générer de glu

test.kt


var str = System.getProperty("hoge") ?: run {
   println("Property was not found!!!")
   return
}

Il est nécessaire de faire cracher une sorte de journal comme ça. L'explication de «run» est omise car elle est hors de cette portée.

Histoire pratique 2

Comme Android View, il ne peut pas être initialisé au moment de l'instanciation, Il existe également des cas où il doit être initialisé dans une méthode spécifique telle que ʻonCreate`.

test.kt


class HogeActivity: AppCompatActivity(){

    private var textView: TextView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.hoge_layout)
        textView = findViewById(R.id.textView) as TextView
    }
}

Puisque textView ne peut être obtenu que s'il est gonflé avec onCreate, La valeur initiale doit être nulle. Dans ce cas, le type sera Nullable comme TextView?.

Il existe deux approches pour rendre ce TextView non nul.

Utilisez le modificateur lateinit

lateinit est un opérateur pour l'évaluation paresseuse de l'initialisation, et la compilation peut être effectuée sans définir la valeur initiale lors de la définition des variables.

test.kt


class HogeActivity: AppCompatActivity(){

    private lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.hoge_layout)
        textView = findViewById(R.id.textView) as TextView
    }
}

Il n'est plus nécessaire de définir la valeur initiale en même temps que la déclaration de variable car? Est supprimé du type textView. La valeur est entrée dans textView pour la première fois avec findViewById.

Cependant, il faut faire attention avec lateinit, c'est qu'il ne peut être utilisé que pour des variables (var). Si getter est appelé avant que setter ne soit appelé, il plantera.

utiliser par paresseux

L'explication de «par» est un peu compliquée par cela seul, donc je ne vais pas l'expliquer en détail, Un modificateur qui vous permet de déléguer les paramètres de propriété à une autre classe. lazy est une fonction qui est exécutée la première fois que vous accédez à une propriété qui définit lazy.

En combinant les deux, l'initialisation des variables peut être effectuée par n'importe quelle fonction d'une autre classe.

test.kt


class HogeActivity: AppCompatActivity(){

    private val textView: TextView by lazy { findViewById(R.id.textView) as TextView }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.hoge_layout)
    }
}

De cette façon, lorsque le getter textView est appelé pour la première fois, il sera avant le getter. findViewById(R.id.textView) as TextView Est exécuté et la valeur initiale est entrée.

Par lazy, au contraire, ne peut être utilisé que pour les constantes (val). Au lieu de cela, vous n'avez pas à vous soucier de planter comme lateinit.

Si vous pouvez utiliser par paresseux, je pense qu'il vaut mieux l'utiliser. Lateinit est-il utilisé dans des cas tels que le poignard DI, qui est défini par une autre classe?

à la fin

La sécurité nulle est une fonctionnalité puissante, mais ce n'est pas une solution miracle qui résout tout. Au contraire, on peut dire qu'il empêche la propagation de défauts à d'autres sources car il tombe avec du gluant.

Lorsque vous utilisez la fonction de sécurité Null, je souhaite comprendre le danger qui se cache derrière elle avant de l'utiliser.

Recommended Posts

[Sécurité Null] Mémo de comparaison Kotlin Java Utilisation correcte de la sécurité Null
[Java] Comparaison correcte du type String
[Java] utilise facultatif au lieu de if (hoge! = Null) {...}
[Java] Comparaison de vitesse de combinaison de chaînes
Génériques Kotlin pour les développeurs Java
Comparaison des types sûrs à tolérance nulle, à tolérance nulle et à tolérance nulle du point de vue de la sécurité nulle
Mémo: [Java] Vérifiez le contenu du répertoire
[Java] [Maven3] Résumé de l'utilisation de Maven3
Mémo de méthode de surveillance des changements de répertoire (Java, Kotlin)
La sécurité Null de Kotlin à envoyer aux développeurs Java
Mémo pour la migration de Java vers Kotlin
[Java] Pourquoi utiliser StringUtils.isEmpty () au lieu de String.isEmpty ()
Mémo Java
Utilisez jenv pour activer plusieurs versions de Java
L'histoire de la comparaison de chaînes de bas niveau en Java
[Java / Kotlin] Redimensionner en tenant compte de l'orientation de l'image