未來的方向:由 Java 到 Kotlin 轉變

zxdposter發表於2022-01-22

前言

Kotlin 非常適合開發伺服器端應用程式,可以讓你編寫簡明且表現力強的程式碼, 同時保持與現有基於Java 的技術棧的完全相容性以及平滑的學習曲線: 表現力:Kotlin 的革新式語言功能,例如支援型別安全的構建器和委託屬性,有助於構建強大而易於使用的抽象。

這是摘錄 kotlin 推廣網站介紹這個語言的一段話,intelliJ 作為一家最懂程式設計師的公司,推出了 kotlin 語言,在使用了一段時間後,我認為 kotlin 完成有資格配得上這段評價。

  1. 非常適合開發伺服器端
  2. 表現力強
  3. 相容 java
  4. 強大易用

通過這段時間對 kotlin 的探索和了解,我想表達一下自己對 kotlin 對個人以及對企業的轉變意義的思考。

轉變的第一步:學好 java

如果是一個對 java 語言不太理解的新手,不太建議一開始就深入的瞭解 kotlin 的運作方式。

kotlin 語法本身是對 java 中很多寫法的封裝,將 java 繁瑣的寫法轉變成風格簡練的 kotlin 寫法,再將 kotlin 最終轉化為 java class。

舉一個簡單的例子:

val str = user?.id

上面一段簡短的 kotlin 語句,轉化為 java,就是:

String str = null
if (user != null) {
    str = user.id
}

最終 kotlin 還是要回歸到 java 之上。

java 本身支撐著龐大的生態,絕大多數的企業、開源庫,都依然還在使用 java 開發,kotlin 能夠做到與 java 本身最大程度的相容,非常不容易。

在可預見的未來裡面,java 依然是開發界的基石,有著不可代替的地位,因此作為一個真正的 kotlin 語言學習者,java 仍然是必修課程。

轉變的第二步:用心理解 kotlin

對一個剛剛接觸 kotlin 的使用者來說,對各種符號、關鍵字的運用,絕對是一大阻力。

如果想能夠快速的明白 kotlin 真正的長處,那麼一定要理解 kotlin 為什麼要這樣幹?

kotlin 為什麼要使用問號 "?"

編寫 java 的過程,最普遍,最困難的就是在處理空指標問題。

一個系統的輸入,要考慮健壯性,必須要定義好哪些變數是可以為空的哪些變數又是不可為空的,當變數為空或者不為空,怎麼去處理,上游程式碼給我的變數到底是不是空的

相信只要是一個考慮問題比較全面的程式設計師,在編寫程式碼時都會有這樣的擔心。

kotlin 的目的就是要消滅程式設計師的擔心。

第一個目的是直接在源頭控制好變數為空或者不為空的情況,這樣程式設計師在每一步的編寫程式碼時,能夠安心的知道,我這個變數是肯定不會為空的,如果是為空的情況,我已經有了應對辦法。

第二個目的,是對可能為空的變數,能夠有非常友好、簡單、可讀性強的處理

var userName = user?.name //當 user 不為空時將屬性 name 複製給變數 userName

user?.let { // 當 user不為空時,列印 name 屬性的值
    println(it.name)
}

user?.name?.let { // 當 user 以及 user.name 不為空時,列印 name 的值
    println(it)
} ?: println("name 為空") // 否則就輸出 name 為空

user?.name = "kotlin" // 當 user 不為空時,給屬性賦值

在這裡可以稍作一下停頓,思考一下在 java 處理這樣的邏輯,需要以怎樣的方式實現。

這種寫法足以打動任何在 java 中多次處理空指標問題、或者在程式碼執行一段時間莫名其妙出現空指標異常的程式設計師。

kotlin 吸收 stream

如果是一個對程式寫法有些追求的程式設計師,相信一定不會錯過 jdk1.8 語法中的 stream 和 lambda。

當我希望將 List<V> 中的 V 的某一個屬性作為鍵轉變為 Map<String, V> 時,stream 已經提供了非常簡潔的寫法:

Map<String, Choice> result = choices.stream().collect(Collectors.toMap(Choice::getName, Function.identity()));

java 已經非常簡潔了,但是我每次希望做這樣一種操作時,每次都在程式碼裡面翻閱或者在網上搜尋一遍用法。

在你使用了 kotlin 的做法後,相信你一定不會忘記它的寫法:

val result = choices.map { it.name to it }.toMap()

對於複雜一些 stream 寫法,你可能需要了解一番 java 如何向 kotlin 轉變的,但是一般寫法,只要求你刪除 stream() 即可。

可以說,kotlin 完全吸收了 stream 的精髓,並且在這之上,青出於藍而勝於藍。

忘記 lombok 和 get set

lomok 是 java 世界中不可忽視的補充力量,他讓簡單的 get set 定義不再被程式設計師需要,但同時它對類的直接修改,也讓很多深入使用的程式設計師詬病。

歸根結底還是由於 java 中的封裝概念,即控制有限欄位暴露。

於是在 kotlin 中,不再有 get set 的概念,只有賦值和直接獲取,只需要利用 privatevalvar 這個幾個關鍵字,就能夠實現控制欄位的可見範圍。

val name: String? = null // 能夠獲取,不能修改

var name: String? = null // 能夠獲取,能夠修改

private val name: String? = null // 不可獲取,不可修改

同樣在 spring boot 中常用的 lombok 註解 @RequiredArgsConstructor,用簡單的建構函式直接生成欄位就能夠代替。

本身 lombok 的註解對 kotlin 程式碼就不生效,當轉變使用 kotlin 時,移除 lombok 也是理所應當的事情。

少就是多

當你能夠理解 kotlin 這三點主要的用途,並能夠應用自如,那麼你將節省至少三分之一的程式碼量。

在程式碼的世界裡,少就是多,減少冗餘程式碼,就是在為自己爭取開發時間,就是問題出現的概率在減少,就是問題發生時排查的速度在提高。

這或許就是 kotlin 為程式設計師積累的經過時間沉澱下來的實實在在的經驗。

轉變的第三步:實踐

當你成功的被 kotlin 簡潔幹練的語法所吸引時,在經過團隊中進步人士的同意下,希望替換為 kotlin 時,請注意到,kotlin 完全相容 java,不僅是 kotlin 努力的方向,責任更在使用者身上。

替換本身是愉快的,之前的程式碼在你的手中一行一行的縮短,一個個空指標判斷在被替換為簡潔的問號,但是風險也在一步步的提高,每進行一步替換都要做好充分的迴歸測試,誰也無法預料在自動 java 到 kotlin 的程式碼轉換器,能否將邏輯推理的那麼嚴謹。

在替換的過程中

  1. 你可會遇到 java static 的方法無法與 kotlin 很好的相容
  2. java 介面中的 default 方法,無法在 mybatis 中的 mapper 介面中應用
  3. 各種意想不到的困難

但是在這些困難背後,解決完後的意義遠大於困難本身,因此這一些都是值得的。

現代語言中的 kotlin 和 swift3

kotlin 語法的誕生不是偶然因素,而且程式碼在不斷髮展過程中的必然結果。

對比 kotlin 與 swift3,你會發現兩者驚人的相似,或許是由於兩個語言中的設計人員有一些重合。

但是這些重合的點,何嘗不是一代代的人使用後積累下來的產物,總是會有人去不斷的追求更高效、更方便、更快捷的開發方式。

這些方式也一定會被現代的語言不斷吸收,這些優點終將會被保留,一直延續到新一代的計算機出現。

對未來 kotlin 的展望

希望 kotlin 語言能夠被更多人和更多的企業接受。

對個人來說接受的不一定是非要使用 kotlin 開發,更多需要接受的是 kotlin 在設計過程彙總爍爍發光的思想方式,不斷要求自己在原本的 java 技能上獲取精進。

對企業來說,減少錯誤成本、降低錯誤率、降低開發時間,永遠是效率為上,理解 kotlin 帶來的價值並能夠合理的加以應用,是重中之重。

同時也希望未來 kotlin 本身能夠再進一層,不再以 java 作為中間語言,而是能夠直接一步到位,擁有完全屬於自己的編寫、編譯、執行的體系。

相關文章