用Java optional模仿Kotlin? - Welsh

banq發表於2022-03-07

讓我們先來看看Optional(在Java8中引入)是做什麼的?

Optional是對一個物件的封裝,提供了安全處理底層物件的方法,同時避免了可怕的空指標異常。

這提供了與Kotlin的nullable資料型別基本相同的行為,並允許Java有辦法模仿Kotlin的nullable資料型別。

而Java沒有的是一個與Kotlin相匹配的非空型別:你不能阻止將null賦值給一個變數。

那麼我們怎麼做呢?

我們可以假設所有不是Optional的東西都是非空的。

最好是為IDE和編譯器的警告做註解,以幫助我們(可能的話還可以使用Lombok在執行時儘可能地執行它):

@Nonnull
String constructMyMessage(@Nonnull final String message,
                          @Nonnull final Optional<String> name) {
  final String userName = name.orElse("unknown person!");
  return userName +" said " + message;
}

/**
  NOTE: This method illustrates handling an optional input and return.
  However, this could be better handled by checking the name optional _before_ calling this method
  (and then woudln't need an optional return).
*/
@Nonnull
Optional<String> maybeConstructAMessage(@Nonnull final String message,
                                        @Nonnull final Optional<String> name) {
  return name.map(evaluatedName -> evaluatedName + " said " + message);
}

注意:所有的Java返回型別和引數都被標記為@Nonnull - 意味著我們不希望在程式碼中看到任何null。

相反,可以使用Optional.empty();這是一個更明確的指示,即不打算存在任何值,而只是缺少。

 

Kotlin:

fun constructMyMessage(message: String, name: String?): String {
  val userName = name ?: "unknown person"
  return "$userName said $message"
}

/**
  NOTE: This method illustrates handling an optional input and return.
  However, this could be better handled by checking the name optional _before_ calling this method
  (and then woudln't need an optional return).
*/
fun maybeConstructAMessage(message: String, name: String?): String? {
    return name?.let { "$it said $message" }
}

 

對於Java來說,這將使Optional Everywhere。

當一個值可能為空時,用一個Optional來包裝它,適用於返回型別、方法引數和成員變數。

 

通過這種方法,你可以避免大多數你可能需要寫null的情況。相反,你可以使用Optional類所提供的方法來操作底層的值。一些有用的方法。

  • ifPresent(Consumer<? super T> consumer)如果值是存在的並且不是空的,就執行consumer 。
  • map(Function<? super T, ? extends U> mapper)使用mapper將底層值轉換為一個新的型別。
  • orElse(T other) 如果底層值為空,則返回底層值或其他。這允許你保證檢索到一個非空值。

還有很多可以用Optionals做的事情,可以在Java 8、11和17文件中找到。

我曾經是隻把Optional作為返回型別的陣營,但在與Kotlin和Swift一起工作後,我已經改用Optional了。

 

這如何適用於集合Collections?

在可能的情況下,如果不需要區分空的情況和空的情況,最好使用空的集合而不是空的集合。如果需要區分空集和空集(比如PATCH請求),可以使用一個Optional來區分集合的兩種狀態。

 

遵循這種方法,你的程式碼庫將更接近於Kotlin,而且還有一個額外的好處,那就是消除了大部分(如果不是全部)你可能遇到的十億美元的錯誤的情況。

 

相關文章