iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0

本日內容為 Effective Kotlin - 3:Eliminate platform types as soon as
possible

Nullable Platform Type

Kotlin 對於空值的安全性是其優勢之一,有助於避免 Java 中經常出現的空指針異常(NPE - NullPointerException)。Java 有滿多好用的函式庫,在開發 Kotlin 會有很大機會用到 JVM 來的值或類型。 當 Kotlin 與其他如 Java 這樣沒有強制的空值安全性的語言交互時,會出現所謂的「平台類型」問題。這種類型的可空性是未知的,且不能在 Kotlin 程式碼中明確表示。

Nullability Annotation

如果我們使用一個聲明 String 作為返回類型的 Java 方法,那麼在 Kotlin 中應該是什麼類型呢?如果它帶有@Nullable 註釋,那麼我們認為它是可為空的,我們將其解釋為 String?。如果它帶有 @NotNull 註釋,那麼我們信任這個註釋,並將其類型為 String。這裡的 Annotation 是一種開發者間的 contract。常見有以下的 nullable 註釋

  • JetBrains - @Nullableand@NotNull from org.jetbrains.annotations
  • Android - @Nullable and @NonNull from androidx.annotation
  • JSR-305 - @Nullable, @CheckForNull and @Nonnull from javax.annotation
  • Eclipse - @Nullableand@NonNull from org.eclipse.jdt.annotation).
  • Lombok - @NonNull from lombok

平台類型 without Nullability Annotation

平台類型 - 一種來自其他語言且其可空性未知的類型

但是,如果這個返回類型既沒有帶 @Nullable 註釋,也沒有帶 @NotNull 註釋,那又應該怎麼辦呢?這個也是常見的平台類型的狀況。平台類型在類型名稱後用一個驚嘆號!來表示,如 String!,但這種表示法不能在程式碼中使用。平台類型是不可表示的,這意味著不能在 Kotlin 中明確地寫出它們。當一個平台值被分配給 Kotlin 變數或屬性時,它可以被推斷,但不能被明確設定。相反,我們可以選擇我們期望的類型:一種是可為空的,一種是非空的類型

假設有一個 Java 方法如下

public class UserRepo {
  public User getUser() {
  //...
  }
}

那在 Kotlin 取用時 type 的宣告就很重要

val repo = UserRepo()
val user1 = repo.user // Type of user1 is User!
val user2: User = repo.user // Type of user2 is User
val user3: User? = repo.user // Type of user3 is User?

將平台類型轉型為非空類型比完全不指定類型要好,但仍然是危險的因為我們認為是非空的東西可能是空的。
基於安全原因,建議是盡快消除這些平台類型。請參考在此例中 statedType 和 platformType 功能的行為差異。

public class JavaClass {
    public String getValue() {
        return null;
    }
}

在 Kotlin 中取用

fun statedType() {
    val value: String = JavaClass().value
    //...
    println(value.length)
}

fun platformType() {
    val value = JavaClass().value
    //...
    println(value.length)
}

兩種情況下都會導致NPE(空指針異常),但這兩種情況下的錯誤發生的地方是不同的。在 statedType 中,NPE會在從Java 獲取值的那一行中被拋出。可以在 debug 時直接找到發生地,並根據這一變更調整我們的 Code。
而在 platformType 中,當我們使用這個值時(可能是從一個更複雜的表達式中),NPE會被拋出,那就會遠離發生地,更糟的是他可能經過層層散撥。像病毒一樣最後才被發現。

料敵從寬、禦敵從嚴

建議作法是會料敵從寬,儘量以 ? 接進來,不管是 JVM 來的。或是前端的 form, 後端的 db, 都假設有為空的可能。經過檢查後再轉成自已 Domain Type, 這樣一來不用一直在 service 處理 Nullable.

結語

因此,當與其他語言交互時,必須格外小心,避免進入Java中類似的困境,即因不當使用對象而導致的NPE。雖然Kotlin 提供了強大的空值安全機制,但在與其他語言的交互中仍需謹慎,以程式碼的穩健性和安全性

每日一推 (G)I-DLE

這首是 (G)I-DLE 進軍美國的 I DO

Yes


上一篇
D06: Immutable 3劍客 Data class 的 copy
下一篇
D08 : 利用 require 與 check 與開發者訂定契約吧
系列文
讓 Kotlin 程式碼更道地 - 談 Effective Kotlin 與相關的 Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言