3

Disons que j'ai code particulier dans le vieux/héritage bibliothèque Java:sécurité nulle dans les bibliothèques Java existantes utilisées dans Kotlin pojects

public class JavaClass { 
    private String notNullString; 
    private String nullableString; 
    private String unannotatedString; 

    public JavaClass(@NotNull String notNullString, 
        @Nullable String nullableString, 
        String unannotatedString) { 

     this.notNullString = notNullString; 
     this.nullableString = nullableString; 
     this.unannotatedString = unannotatedString; 
    } 

    @NotNull 
    public String getNotNullString() { 
     return notNullString; 
    } 

    @Nullable 
    public String getNullableString() { 
     return nullableString; 
    } 

    public String getUnannotatedString() { 
     return unannotatedString; 
    } 
} 

Les deux premiers paramètres sont correctement annotés avec @NotNull et annotations @Nullable (en utilisant JetBrains .annotations). Le troisième (unnanotatedString) est laissé sans annotation appropriée.

Lorsque j'utilise cette classe dans mon code Kotlin et mis tous les arguments du constructeur à des valeurs non nulles, tout va bien:

val foo = JavaClass("first string", "second string", "third string") 

println("Value1: ${foo.notNullString.length}") 
println("Value2: ${foo.nullableString?.length}") 
println("Value3: ${foo.unannotatedString.length}") 

La première valeur est non nulle pour que je puisse y accéder sans appel sécurisé. Deuxième valeur et je dois utiliser safe call (nullableString? .length), sinon, j'ai une erreur de compilation, jusqu'ici tout va bien. Sur la troisième valeur (unannotatedString) je peux l'utiliser sans un appel sûr, il compile bien.

Mais quand je mets le troisième paramètre à « null » Je ne suis pas une erreur de compilation (pas d'appel en toute sécurité nécessaire, seulement la durée d'exécution NullPointerException:

val bar = JavaClass("first string", "second string", null) 

println("Value4: ${bar.unannotatedString.length}") // throws NPE 

Est-ce que le comportement attendu est le compilateur de Kotlin? ? pas de traitement annotée méthodes Java mêmes que ceux annotés avec @NotNull

Répondre

5

Le type de cette variable à la vue de Kotlin sera String!, qui est un platform type. Initialement, toutes les variables provenant de Java étaient validables, mais elles ont changé cette décision plus tard lors de la conception du langage, car elles nécessitaient trop de manipulation et nécessitaient trop d'appels sécurisés qui encombraient le code. Au lieu de cela, c'est à vous d'évaluer si un objet provenant de Java peut être null, et de marquer leur type en conséquence. Le compilateur n'applique pas de sécurité nulle pour ces objets.


À titre d'exemple supplémentaire, si vous surchargeons une méthode de Java, les paramètres sont les types de plate-forme encore une fois, et il est à vous si vous les marquer annulable ou non. Si vous avez cette interface Java:

interface Foo { 
    void bar(Bar bar); 
} 

Ensuite, ce sont les deux implémentations valides de dans Kotlin:

class A : Foo { 
    fun bar(bar: Bar?) { ... } 
} 

class B : Foo { 
    fun bar(bar: Bar) { ... } 
} 
4

Chaque fois que le compilateur Kotlin ne sait pas ce que le type de valeur NULL est, le type devient un platform type, désigné par une !:

public String foo1() { ... } 
@NotNull public String foo2() { ... } 
@Nullable public String foo3() { ... } 

val a = foo1() // Type of a is "String!" 
val b = foo2() // Type of b is "String" 
val c = foo3() // Type of c is "String?" 

Cela signifie un peu comme, "Je ne sais pas quel est le type, vous devrez peut-être le vérifier".

Le compilateur Kotlin n'applique pas de vérification nulle sur ces types, car il peut être inutile:

Toute référence en Java peut être nulle, ce qui rend les exigences de Kotlin de nul-sécurité stricte pratique pour les objets venant de Java. (...) Lorsque nous appelons des méthodes sur des variables de types de plate-forme, Kotlin n'émet pas d'erreurs de nullité au moment de la compilation, mais l'appel peut échouer à runtime, en raison d'une exception null-pointer ou d'une assertion générant Kotlin pour empêcher de se propager nulls:

val item = list[0] // platform type inferred (ordinary Java object) 
item.substring(1) // allowed, may throw an exception if item == null