從0到1學(xué)習(xí)Kotlin

近半年因業(yè)務(wù)需要,帶領(lǐng)團(tuán)隊(duì)成員新開發(fā)一款A(yù)PP并順利上線,目前已迭代2個(gè)版本。眾所周知,2019年Google I/O大會(huì)上宣布Kotlin-first,因?yàn)轫?xiàng)目最開始,我們便制定了APP全部代碼由Kotlin實(shí)現(xiàn)的目標(biāo)。項(xiàng)目告一段落后,因此整理一篇文章,一是在團(tuán)隊(duì)中分享給更多成員,二是鞏固已有知識(shí)。前言結(jié)束~

一. Kotlin語言的發(fā)展歷史

Kotlin是一門在JVM上運(yùn)行的靜態(tài)類型編程語言,也可以被編譯成為JavaScript源代碼。由JetBrains開發(fā)(1200+員工)。"Kotlin"命名取自圣彼得堡附近的一座島嶼名稱。Kotlin是根據(jù)Apache 2.0授權(quán)的免費(fèi)開源項(xiàng)目:JetBrains/kotlin

  • 2011年7月,JetBrains推出Kotlin項(xiàng)目(已開發(fā)1年之久)
  • 2012年2月,JetBrains以Apache 2許可證開源此項(xiàng)目
  • 2016年2月,Kotlin v1.0發(fā)布
  • 2017年5月,Google在I/O大會(huì)上宣布:Kotlin為Android開發(fā)一級(jí)語言
  • 2019年5月,Google在I/O大會(huì)上宣布:Kotlin-first,成為Android開發(fā)首選語言
    Android Studio新建Project默認(rèn)語言是Kotlin.png
  • 2020年3月,發(fā)布最新版本v1.3.71



JetBrains團(tuán)隊(duì)創(chuàng)建Kotlin項(xiàng)目的主要目標(biāo):

  • 創(chuàng)建一種兼容Java的語言
  • 編譯速度至少同Java一樣快
  • 比Java更安全
  • 比Java更簡(jiǎn)潔



為什么Kotlin會(huì)得到Google支持?

  • 與Oracle曠日持久的Java侵權(quán)案:最新結(jié)果Google敗訴,需向Oracle賠償88億美元。起因:Oracle起訴Android中無償使用了37個(gè)Java APIs,侵犯專利;同時(shí)有9行代碼抄襲了Java
  • Kotlin自身的語言優(yōu)點(diǎn)



Android官方Kotlin示例:



Kotlin構(gòu)建的應(yīng)用:



Stack Overflow Developer Survey 2019的結(jié)果中:

  • 最受喜愛的編程語言排名第4,72.6%(Top 1:Rust 83.5%,Java排名第18:53.4%)
  • 6.4%的人使用Kotlin編程 (Top 1:JavaScript 67.8%,Java排名第5:41.1%)


二. Kotlin適用范圍


重點(diǎn)解釋下服務(wù)端、Web開發(fā)、Android:
1. 服務(wù)端:

  • Spring、Vert.x、Ktor、kotlinx.html等均對(duì)Kotlin提供支持
  • 可伸縮性:Kotlin 對(duì)協(xié)程的支持有助于構(gòu)建服務(wù)器端應(yīng)用程序, 伸縮到適度的硬件要求以應(yīng)對(duì)大量的客戶端

協(xié)程:一個(gè)線程在執(zhí)行函數(shù)時(shí),如果遇到如I/O等阻塞操作,線程可以主動(dòng)控制,去操作其他函數(shù),等I/O等阻塞操作完成,再回來繼續(xù)執(zhí)行原函數(shù)。是一種“偽多線程”,無需線程上下文切換的開銷,效率高

2. Web開發(fā):

  • Kotlin可編譯為JavaScript
  • 支持與DOM元素交互、支持與圖形(如WebGL)交互、支持JQuery和ReactJS等第三方庫和框架、兼容CommonJS等

3. Android:

  • Android官方支持Kotlin
  • 舉例:Keepsafe的App Lock應(yīng)用已100%轉(zhuǎn)換為Kotlin,源代碼行數(shù)減少30%,方法數(shù)減少10%


三. Kotlin VS Java

相比Java,Kotlin的優(yōu)點(diǎn):
1. 代碼簡(jiǎn)潔
經(jīng)典例子:

Java

Kotlin

以上針對(duì)Person類,Java和Kotlin的實(shí)現(xiàn)一致,但Kotlin代碼行數(shù)減少24行。

Kotlin默認(rèn)幫類的成員變量設(shè)置了getter、setter方法,實(shí)現(xiàn)是:
var id: String? = null
set(value : String?) {
id = value // field = value
}
// 以上代碼有一個(gè)bug,你發(fā)現(xiàn)了嗎?如果使用id=value,會(huì)造成set函數(shù)的無限遞歸調(diào)用,最終導(dǎo)致stackoverflow,在Kotlin中默認(rèn)setter方法中需使用field代替類成員變量,避免set的默認(rèn)調(diào)用

另外簡(jiǎn)潔性,可參考對(duì)比示例:from-java-to-kotlin

2. 安全性強(qiáng):改善空指針問題

  • Top 5 Crashes on Android,Top 1 NullPointerException
  • 圖靈獎(jiǎng)得主Tony Hoare在1965年設(shè)計(jì)ALGO W編程語言時(shí)引入Null引用,2009年,QCon大會(huì)上Tony稱這是"十億美元的錯(cuò)誤"
    由上可知空指針問題的嚴(yán)重性,而Kotlin天然的創(chuàng)造性提出可空非空類型,代碼階段就很好減少空指針問題出現(xiàn)的可能性

3. 互操作性:充分利用JVM、Android和瀏覽器現(xiàn)有庫

與Java代碼完全可互相操作,.java文件、.kt文件都是編譯為.class文件,不過編譯過程還是有區(qū)別,編譯前端(詞法分析/語法分析/語義分析/中間代碼生成)與Java基本一致,編譯后端有區(qū)別(做了很多代碼封裝工作,例如自動(dòng)生成Getter/Setter方法等,將代碼層的很多封裝工作轉(zhuǎn)移到編譯后端,這也是Kotlin語言簡(jiǎn)潔的原因)

4. 工具友好:IntelliJ IDEA/Adroid Studio/Eclipse等支持

最后,從語法上舉幾個(gè)明顯的差異例子:

  • Kotlin創(chuàng)建對(duì)象無需new關(guān)鍵詞
  • Kotlin每行代碼后無需加";"分號(hào)
  • Kotlin主動(dòng)推斷變量類型(var/val),無需特別聲明
  • Kotlin的文件類型是*.kt
  • Kotlin方法定義要加關(guān)鍵詞fun

更多與Java的語言特性比較:參考 http://shouce.jb51.net/kotlin/txt/comparison-to-java.html


四. 語法糖

1. 變量

1.1 Kotlin是一種靜態(tài)類型的語言,編譯器根據(jù)所賦值的類型來推斷類型,類型在編譯時(shí)解析確定且從不改變。聲明變量的2個(gè)關(guān)鍵字:var、val

var 變量值可以更改
val 變量值賦值后不能更改

注意:
var a   // 局部變量編譯錯(cuò)誤:The variable must either have a type annotation or be initialized
改為:
var a : String  //正確
var a = "test"  //正確

1.2 Kotlin中類型是默認(rèn)的非空值,如果變量是一個(gè)可空類型,聲明時(shí)需要添加"?",例如:

var a : String? = null   // 正確
var a : String = null     // 編譯錯(cuò)誤
備注:某種程度上,你可以認(rèn)為非空String 和 可空String是兩個(gè)不同類型

1.3 如果變量是可空類型,調(diào)用時(shí)必須增加"?"空檢查,例如:

println (a?.length) // 正確,等于: if (a != null) println(a.length);
println (a.length) // 編譯錯(cuò)誤

1.4 雙嘆號(hào)!!表示在對(duì)象不為空的情況下執(zhí)行,如果對(duì)象為空,則執(zhí)行時(shí)拋出NullPointerException,例如:

val a : String ?= null
a!!.length;

1.5 類的成員變量需聲明時(shí)初始化,或聲明abstract,或者init函數(shù)中初始化,或者使用lateinit var延遲初始化。另外延遲初始化還可以使用by lazy,區(qū)別是:lateinit var僅支持類成員變量,要求變量是var;by lazy支持類成員變量/局部變量,要求變量是val

private var a : String? // 編譯錯(cuò)誤
private lateinit var a : String? // 正確
private abstract var a : String? // 正確
private var a : String?
init { a = null } // 正確

備注1:這里也是與Java語法區(qū)別,Java中類成員變量可不初始化,有默認(rèn)值
備注2:Kotlin提供了isInitialized函數(shù)來判斷變量是否已初始化/賦值

1.6 類的成員變量有這4個(gè)可見性修飾符:privateprotected、 internalpublic。 如果沒有顯式指定修飾符的話,默認(rèn)可見性是 public。備注:private < protected < internal < public,其中internal指類聲明的本模塊內(nèi)可見:

模塊是指編譯在一起的1套 Kotlin 文件,可以是:
- 1個(gè) IntelliJ IDEA 模塊
- 1個(gè) Maven 項(xiàng)目
- 1個(gè) Gradle 源集(例外是 test 源集可以訪問 main 的 internal 聲明)
- 1次 <kotlinc> Ant 任務(wù)執(zhí)行所編譯的一套文件
2.條件語句支持if-else、when。when表達(dá)式的每一個(gè)分支由一個(gè)條件、一個(gè)箭頭(→)和一個(gè)結(jié)果來表示
3. 標(biāo)準(zhǔn)函數(shù):let、with、run、apply、also

let函數(shù):

object.let{
      it.todo()     // 函數(shù)內(nèi)it代替object,可訪問其屬性和方法
}

使用場(chǎng)景:
場(chǎng)景一:最常用的場(chǎng)景就是使用let函數(shù)處理需要針對(duì)一個(gè)可null的對(duì)象統(tǒng)一做判空處理
              object?.fun1()
              object?.fun2()
              使用let函數(shù)后:object?.let {
                                                       it.fun1()
                                                       it.fun2() }
場(chǎng)景二:然后就是需要去明確一個(gè)變量處特定的作用域范圍內(nèi)可以使用

with、run、apply、also等函數(shù):

with(object) { // object作為函數(shù)參數(shù),函數(shù)塊內(nèi)可使用this代替object,返回值為最后一行或return指定
      // todo
}
object.run{     // run相當(dāng)于let和with結(jié)合體
      // todo
}
object.apply{   // apply和run很像,區(qū)別是返回值不一樣,apply函數(shù)返回傳入的對(duì)象本身 
      // todo
}
object.also{     // also和let很像,區(qū)別是返回值不一樣,also函數(shù)返回傳入的對(duì)象本身
     // todo
}
4. 伴生對(duì)象 companion object,與類綁定的一個(gè)單例對(duì)象(編譯后.class中轉(zhuǎn)換成static對(duì)象),例如:
class MyClass {
    companion object {
        val logger = LoggerFactory.getLogger(MyClass::class.java) 
    }
}
5. 一些注解:

5.1 @JvmOverloads:在有默認(rèn)參數(shù)值的方法中使用此注解,此方法會(huì)暴露多個(gè)方法

@JvmOverloads fun f(a: String, b: Int=0){ }
相當(dāng)于:
fun f(a: String){
    b = 0;
    // ...
}
fun f(a: String, b: Int){}


五. Google建議使用Kotlin最佳實(shí)踐

    1. 側(cè)重于可讀性,而不是盡量縮短代碼行。用 Kotlin 語法糖很容易過度。
    1. 確立最適合自己團(tuán)隊(duì)的編碼規(guī)范和慣用語。


六. 參考

  1. from-java-to-kotlin
  2. Android Kotlin官網(wǎng)
  3. FQA - Kotlin語言中文站
  4. Stack Overflow Developer Survey 2019
  5. Kotlin語言中文站
  6. Kotlin 勢(shì)必取代 Java?
  7. Kotlin 編譯之路 "Kotlin編譯器"





作者:kevin song,2020.6.22于南京建鄴區(qū)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容