2017-06-14 38 views
3

比方說,我在老/遺留Java庫特定代碼:空安全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; 
    } 
} 

前兩個參數都正確地@NotNull和@Nullable註解(使用JetBrains公司.annotations)。第三個(unnanotatedString)沒有適當的註釋。

當我在科特林代碼中使用這個類,所有構造函數的參數設置爲非空值,一切都很好:

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

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

第一個值不爲空,所以我可以不用訪問安全通話。第二個值,我需要使用安全調用(nullableString?.length),如果沒有,我有一個編譯時錯誤,到目前爲止這麼好。在第三個值(unannotatedString)我可以使用它沒有一個安全的調用,它編譯好。

但是,當我設置的第三個參數爲「空」我沒有得到一個編譯時錯誤(無需安全通話,僅在運行NullPointerException異常:

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

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

那是預期的行爲是科特林的編譯器? ?治療不帶註釋的Java方法相同,與@NotNull註釋的那些

回答

5

類型從科特林的觀點,即變量的將是String!,這是一個platform type

他們最初使每個變量都來自Java可爲空,但他們稍後在設計語言期間更改了該決定,因爲它需要太多的處理並需要太多的安全調用來混淆代碼。

取決於您評估來自Java的對象是否可能是null,並相應地標記其類型。編譯器不強制這些對象的null安全。


作爲一個附加的例子,如果你覆蓋了從Java方法,參數將是平臺類型再次,它取決於你是否將它們標記爲可爲空或不是。如果你有這樣的Java接口:

interface Foo { 
    void bar(Bar bar); 
} 

然後這些都是它都有效實現在科特林:

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

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

每當科特林編譯器不知道類型爲空是什麼,類型變成platform type,與單一!表示:

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?" 

這意味着更多,「我不知道類型是什麼,你可能需要檢查它」。

的科特林編譯器不強制執行這些類型的空檢查,因爲這可能是不必要的:

在Java中的任何參考可以爲null,這使得科特林的要求嚴格的空安全不切實際的對象 來自Java。 (...) 當我們調用平臺類型變量的方法時,Kotlin不會在編譯時發出可空性錯誤,但由於空指針異常或Kotlin生成的斷言,調用可能會失敗,因爲運行時可能會出現 運行時錯誤防止空值從傳播:

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