iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
Software Development

每天罵爆一隻 Kafka Pull Request系列 第 17

KAFKA-12895 KIP-751: Drop support for Scala 2.12 in Kafka 4.0 (deprecate in 3.0) part 2

  • 分享至 

  • xImage
  •  

https://github.com/apache/kafka/pull/17313#discussion_r1781495806

背景故事

今天延續上一篇的文章,不過來討論一個離kafka比較遠的題目,但卻是在Kafka不斷被提到的東西,那就是ScalaJava之間的各種轉換。為什麼會有這個議題?有讀過前面文章的朋友一定馬上能猜到原因,沒錯,那就是Kafka目前只剩下伺服器核心元件還是Scala ,其他都已經是Java了。因此在許多邏輯操作上就必須面對資料結構兩邊的互相轉換,當然可能有人會說為什麼不統一都用Java資料結構?這是歷史的關係Scala是先出現而後來才開始轉而用Java,所以要一次全部改用Java的資料結構會需要很長很長的一段時間。因此在Kafka內部採用了大量Java結構轉換成Scala的寫法,而這也帶出今天的主題:Java資料結構直接轉成Scala之後的語義是否一致?而這次要討論的主角就是ScalagetOrElseUpdate(key: K, defaultValue: => V)

getOrElseUpdate(key: K, defaultValue: => V)說文解字就是當key存在時則回傳對應的值,反之則會執行defaultValue取得新的值後放入資料結構裡面後回傳。這聽起來是一個很常見的故事,甚至大家會直接聯想到Java版本的computeIfAbsent,對吧?我們來看一下Scala如何包裝JavaConcurrentHashMap

override def getOrElseUpdate(key: K, op: => V): V =
  underlying.computeIfAbsent(key, _ => op) match {
    case null => super/*[concurrent.Map]*/.getOrElseUpdate(key, op)
    case v    => v
  }

是不是有一種「阿果然如此」,就是直接呼叫computeIfAbsent來完成getOrElseUpdate的需求 ... 欸等等,為什麼null的時候還要另外呼叫一次super.getOrElseUpdate? 原因很簡單,那就是computeIfAbsentgetOrElseUpdate兩者對於null的態度不一樣。computeIfAbsent當計算結果爲null的時候不會放進資料結構裡面,類似下方的邏輯:

if (map. get(key) == null) {
  V newValue = mappingFunction. apply(key);
  if (newValue != null) map. put(key, newValue); 
}

然而getOrElseUpdate在語義上則是計算出來的值一定會放到資料結構,就算該值爲null,當然如果實作上是不允許null的一樣會噴出錯誤。而這兩者在語義上的差異自然就導致Scala在包裝Java時需要額外處理null的問題,畢竟對於Scala而言包裝後的物件一定要符合Scala的語義,所以當computeIfAbsent最後結果爲null時,Scala就必須額外想辦法把該值放到資料結構裡面。看到這裏大家可能會有一個疑問,那就直接再呼叫put不就好了?但很可惜在併發的世界裡這樣會失去原子性,這也是爲何Scala是選擇呼叫getOrElseUpdate來嘗試把null放到資料結構裡面。

等等,如果又呼叫一次getOrElseUpdate,那麼用來產生資料的方法不就可能會被呼叫很多次?沒錯,這就是一個需要注意的地方,ConcurrentHashMap在實作上是有保證用來產生資料的方法一定只會呼叫一次,但如果你今天為了要轉換成Scala而重新包裝,那麼在上述null的情況下用來產生資料的方法就可能會被反覆呼叫很多次!

解決辦法

如果你今天很確定使用情境不會有產生null的狀況,自然就不用擔心這個問題。反之,則必須要注意產生資料的方法本身不能具有副作用,例如改變某些狀態之類的。又或者乾脆一點,別再用Scala的包裝了,就直接大方的使用Java的界面吧!

廣告

歡迎訂閱全臺最鬆散的開源社群源來適你,上面不定期會有各種開源的廢文。也歡迎參加全臺最鬆散的開源討論頻道,上面有一群網友一起在刷開源技術


上一篇
KAFKA-12895 KIP-751: Drop support for Scala 2.12 in Kafka 4.0 (deprecate in 3.0)
下一篇
KAFKA-17589 Move JUnit extensions to test-common module
系列文
每天罵爆一隻 Kafka Pull Request30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言