Kotlin 到底是什么 ? 它是一種針對(duì) Java 平臺(tái)的新編程語(yǔ)言。Kotlin 簡(jiǎn)潔、安全、務(wù)實(shí),并且專(zhuān)注于與 Java 代碼的互操作性。它幾乎可以用在現(xiàn)在 Java 使用的任何地方 :服務(wù)器端開(kāi)發(fā)、Android 應(yīng)用,等等。Kotlin 可以很好地和所有現(xiàn)存的 Java 庫(kù)和框架一起工作,而且性能水平和 Java 旗鼓相當(dāng)。本文我們將詳細(xì)地探討 Kotlin 的主要特征。

讓我們從一個(gè)小例子開(kāi)始,來(lái)看看 Kotlin 代碼長(zhǎng)什么樣子。這個(gè)例子定義了一個(gè) Person 類(lèi)來(lái)表示“人”,創(chuàng)建一個(gè)“人”的集合,查找其中年紀(jì)大的人,并打印結(jié)果。盡管這是非常小的一段代碼,從中也可以看到 Kotlin 許多有趣的特性。
我們對(duì)其中的一些特性做了標(biāo)記,以便你可以方便地在本書(shū)后續(xù)的內(nèi)容中找到它們。
代碼簡(jiǎn)要地進(jìn)行了解釋?zhuān)侨绻行﹥?nèi)容你現(xiàn)在還無(wú)法理解,請(qǐng)不要擔(dān)心,稍后我們會(huì)詳細(xì)討論。
如果你想嘗試運(yùn)行這個(gè)例 子,簡(jiǎn)單的方法是使用 http://try.kotl.in 的在線 Playground。輸入示例代碼并單擊 Run 按鈕,代碼將會(huì)執(zhí)行。
代碼清單 1.1 Kotlin 初體驗(yàn)
你聲明了一個(gè)簡(jiǎn)單的數(shù)據(jù)類(lèi),它包括了兩個(gè)屬性:name和age。age屬性默認(rèn)為null(如果沒(méi)有指定)。在創(chuàng)建“人”的列表時(shí),你省略了Alice的年齡,所以這里年齡使用了默認(rèn)值null。然后你調(diào)用了maxBy函數(shù)來(lái)查找列表中年紀(jì)大的那個(gè)“人”。傳遞給這個(gè)函數(shù)的lambda表達(dá)式需要一個(gè)參數(shù),使用it作為這個(gè)參數(shù)的默認(rèn)名稱(chēng)。如果age屬性為null,Elvis運(yùn)算符(?:)會(huì)返回零。因?yàn)锳lice的年齡沒(méi)有指定,Elvis運(yùn)算符使用零代替了它,所以Bob幸運(yùn)地成了年紀(jì)大的人。
喜歡這樣的代碼嗎 ? 繼續(xù)讀下去,你將會(huì)學(xué)習(xí)到更多,并成為一名 Kotlin 專(zhuān)家。我們希望不久之后,在你自己的項(xiàng)目中也能看到這樣的代碼,而不只是在書(shū)上。

你大概已經(jīng)知道了 Kotlin 是一種怎樣的語(yǔ)言,讓我們更加深入地了解一下它的關(guān)鍵屬性。首先,我們來(lái)看看你能用 Kotlin 創(chuàng)造哪些種類(lèi)的應(yīng)用程序。
目標(biāo)平臺(tái) :服務(wù)器端、Android 及任何 Java 運(yùn)行的地方
Kotlin 的首要目標(biāo)是提供一種更簡(jiǎn)潔、更高效、更安全的替代 Java 的語(yǔ)言,并且適用于現(xiàn)今使用 Java 的所有環(huán)境。Java 是一門(mén)非常受歡迎的語(yǔ)言,它廣泛地應(yīng)用于不同的環(huán)境 :小到智能卡 (JavaCard 技術(shù) ),大到 Google、Twitter、LinkedIn 和其他這種規(guī)模的互聯(lián)網(wǎng)公司運(yùn)行的大的數(shù)據(jù)中心。在這些地方,使用 Kotlin 可以幫助開(kāi)發(fā)者在實(shí)現(xiàn)目標(biāo)的同時(shí)減少代碼并避免麻煩。
Kotlin 常見(jiàn)的應(yīng)用場(chǎng)景有 :
編寫(xiě)服務(wù)器端代碼(典型的代表是 Web 應(yīng)用后端)
創(chuàng)建 Android 設(shè)備上運(yùn)行的移動(dòng)應(yīng)用
但 Kotlin 還有其他用武之地。例如,可以使用 Intel Multi-OS Engine((https:// software.intel.com/en-us/multi-os-engine)讓 Kotlin 代碼運(yùn)行在 iOS 設(shè)備上。還可以 使用 Kotlin 和 TornadoFX(https://github.com/edvin/tornadofx)以及 JavaFX(http://mng.bz/500y) 一起來(lái)構(gòu) 建桌面應(yīng)用程序。
除了 Java 之外,Kotlin 還可以編譯成 JavaScript,允許你在瀏覽器中運(yùn)行 Kotlin 代碼。但截止本書(shū)撰寫(xiě)時(shí),對(duì) JavaScript 的支持仍在 JetBrains 內(nèi)部探索并進(jìn)行原型 開(kāi)發(fā),這超出了本書(shū)的范圍,而其他一些平臺(tái)也在考慮支持 Kotlin 的未來(lái)版本。
正如你所看到的,Kotlin 的目標(biāo)平臺(tái)是相當(dāng)廣泛的。Kotlin 并沒(méi)有被限制在單 一的問(wèn)題域,也沒(méi)有被限制在解決軟件開(kāi)發(fā)者面臨的某一類(lèi)型的挑戰(zhàn)。相反,對(duì)所 有開(kāi)發(fā)過(guò)程中涌現(xiàn)的任務(wù),Kotlin 都提供了全面的生產(chǎn)力提升。它借助支持特定領(lǐng) 域或編程范式的庫(kù),提供了卓越的集成水準(zhǔn)。接下來(lái)讓我們來(lái)看看 Kotlin 作為一種 編程語(yǔ)言的關(guān)鍵特質(zhì)。
靜態(tài)類(lèi)型
Kotlin 和 Java 一樣是一種靜態(tài)類(lèi)型的編程語(yǔ)言。這意味著所有表達(dá)式的類(lèi)型在 編譯期已經(jīng)確定了,而編譯器就能驗(yàn)證對(duì)象是否包含了你想訪問(wèn)的方法或者字段。
這與 動(dòng)態(tài)類(lèi)型 的編程語(yǔ)言形成了鮮明的對(duì) 比,后者在 JVM 上的代表包括 Groovy 和 JRuby。這些語(yǔ)言允許你定義可以存儲(chǔ)任何數(shù)據(jù)類(lèi)型的變量,或者返回任 何數(shù)據(jù)類(lèi)型的函數(shù),并在運(yùn)行時(shí)才解析方法和字段引用。這會(huì)減少代碼量并增加創(chuàng) 建數(shù)據(jù)結(jié)構(gòu)的靈活性。但它的缺點(diǎn)是,在編譯期不能發(fā)現(xiàn)像名字拼寫(xiě)錯(cuò)誤這樣的問(wèn)題,繼而導(dǎo)致運(yùn)行時(shí)的錯(cuò)誤。
另一方面,與 Java 不同的是,Kotlin 不需要你在源代碼中顯式地聲明每個(gè)變量 的類(lèi)型。很多情況下,變量類(lèi)型可以根據(jù)上下文來(lái)自動(dòng)判斷,這樣就可以省略類(lèi)型聲明。這里有一個(gè)可能是簡(jiǎn)單的例子 :
val x = 1
在聲明這個(gè)變量時(shí),由于變量初始化為整型值,Kotlin 自動(dòng)判斷出它的類(lèi)型是 Int。編譯器這種從上下文推斷變量類(lèi)型的能力被稱(chēng)作類(lèi)型推導(dǎo)。
下面羅列了一些靜態(tài)類(lèi)型帶來(lái)的好處 :
性能——方法調(diào)用速度更快,因?yàn)椴恍枰谶\(yùn)行時(shí)才來(lái)判斷調(diào)用的是哪個(gè)方法。
可靠性——編譯器驗(yàn)證了程序的正確性,因而運(yùn)行時(shí)崩潰的概率更低。
可維護(hù)性——陌生代碼更容易維護(hù),因?yàn)槟憧梢钥吹酱a中用到的對(duì)象的類(lèi)型。
工具支持——靜態(tài)類(lèi)型使 IDE 能提供可靠的重構(gòu)、精確的代碼補(bǔ)全以及其他 特性。
得益于 Kotlin 對(duì)類(lèi)型推導(dǎo)的支持,你不再需要顯式地聲明類(lèi)型,因此大部分關(guān) 于靜態(tài)類(lèi)型的額外冗長(zhǎng)代碼也就不復(fù)存在了。
當(dāng)你檢視 Kotlin 類(lèi)型系統(tǒng)的細(xì)節(jié)時(shí),你會(huì)發(fā)現(xiàn)許多熟悉的概念。類(lèi)、接口以及 泛型和 Java 非常接近,所以大部分的 Java 知識(shí)可以很容易地轉(zhuǎn)移到 Kotlin。然而, 也會(huì)有一些新概念出現(xiàn)。
其中重要的概念是 Kotlin 對(duì)可空類(lèi)型的支持,通過(guò)在編譯期檢測(cè)可能存在的 空指針異常,它讓你可以寫(xiě)出更可靠的程序。
另一個(gè) Kotlin 類(lèi)型系統(tǒng)的新概念是對(duì)函數(shù)類(lèi)型的支持。要搞清楚這一點(diǎn),我們 先要了解函數(shù)式編程的主要思想,以及 Kotlin 是如何支持這種編程風(fēng)格的。
函數(shù)式和面向?qū)ο?/strong>
作為一個(gè) Java 開(kāi)發(fā)者,你一定對(duì)面向?qū)ο缶幊痰暮诵母拍顮€熟于胸,但函數(shù)式 編程對(duì)你來(lái)說(shuō)卻可能很新鮮。函數(shù)式編程的核心概念如下 :
頭等函數(shù)——把函數(shù)(一小段行為)當(dāng)作值使用,可以用變量保存它,把它 當(dāng)作參數(shù)傳遞,或者當(dāng)作其他函數(shù)的返回值。
不可變性——使用不可變對(duì)象,這保證了它們的狀態(tài)在其創(chuàng)建之后不能再變 化。
無(wú)副作用——使用的是純函數(shù)。此類(lèi)函數(shù)在輸入相同時(shí)會(huì)產(chǎn)生同樣的結(jié)果, 并且不會(huì)修改其他對(duì)象的狀態(tài),也不會(huì)和外面的世界交互。
函數(shù)式編程風(fēng)格的代碼能給你帶來(lái)什么好處 ? 首先,簡(jiǎn)潔。函數(shù)式風(fēng)格的代碼 比相應(yīng)的命令式風(fēng)格的代碼更優(yōu)雅、更簡(jiǎn)練,因?yàn)榘押瘮?shù)當(dāng)作值可以讓你獲得更強(qiáng) 大的抽象能力,從而避免重復(fù)代碼。
假設(shè)你有兩段類(lèi)似的代碼,實(shí)現(xiàn)相似的任務(wù)(例如,在集合中尋找一個(gè)匹配的 元素)但具體細(xì)節(jié)略有不同(如何判斷元素是匹配的)。可以輕易地將這段邏輯中公 共的部分提取到一個(gè)函數(shù)中,并將其他不同的部分作為參數(shù)傳遞給它。這些參數(shù)本身也是函數(shù),但你可以使用一種簡(jiǎn)潔的語(yǔ)法來(lái)表示這些匿名函數(shù),它被稱(chēng)作 lambda 表達(dá)式 :
函數(shù)式編程風(fēng)格的代碼帶來(lái)的第二個(gè)好處是多線程安全。多線程程序中大的錯(cuò)誤來(lái)源之一就是,在沒(méi)有采用適當(dāng)同步機(jī)制的情況下,在不同的線程上修改同一份數(shù)據(jù)。如果你使用的是不可變數(shù)據(jù)結(jié)構(gòu)和純函數(shù),就能保證這樣不安全的修改根 本不會(huì)發(fā)生,也就不需要考慮為其設(shè)計(jì)復(fù)雜的同步方案。
后,函數(shù)式編程意味著測(cè)試更加容易。沒(méi)有副作用的函數(shù)可以獨(dú)立地進(jìn)行測(cè) 試,因?yàn)椴恍枰獙?xiě)大量的設(shè)置代碼來(lái)構(gòu)造它們所依賴(lài)的整個(gè)環(huán)境。
一般來(lái)說(shuō),函數(shù)式編程風(fēng)格可以在任何編程語(yǔ)言中使用(包括 Java),它的很 多主張都被認(rèn)為是良好的編程風(fēng)格。然而并不是所有的語(yǔ)言都提供了語(yǔ)法和庫(kù)支持, 讓我們可以毫不費(fèi)力地使用這種風(fēng)格。例如,Java 8 之前的 Java 版本都缺少了這種 支持。Kotlin 擁有豐富的特性集從一開(kāi)始就支持函數(shù)式編程風(fēng)格,包括 :
函數(shù)類(lèi)型,允許函數(shù)接受其他函數(shù)作為參數(shù),或者返回其他函數(shù)。
lambda 表達(dá)式,讓你用少的樣板代碼方便地傳遞代碼塊
數(shù)據(jù)類(lèi),提供了創(chuàng)建不可變值對(duì)象的簡(jiǎn)明語(yǔ)法
標(biāo)準(zhǔn)庫(kù)中包括了豐富的 API 集合,讓你用函數(shù)式編程風(fēng)格操作對(duì)象和集合
Kotlin 允許你使用函數(shù)式編程風(fēng)格但并沒(méi)有強(qiáng)制你使用它。當(dāng)你需要的時(shí)候, 可以使用可變數(shù)據(jù),也可以編寫(xiě)帶副作用的函數(shù),而且不需要跳過(guò)任何多余的步驟。 然后,毫無(wú)疑問(wèn)的是,在 Kotlin 中使用基于接口和類(lèi)層次結(jié)構(gòu)的庫(kù)就像 Java 一樣簡(jiǎn) 單。當(dāng)編寫(xiě) Kotlin 代碼的時(shí)候,可以結(jié)合使用面向?qū)ο缶幊毯秃瘮?shù)式編程風(fēng)格,并 使用合適的工具來(lái)對(duì)付亟待解決的問(wèn)題。
免費(fèi)并開(kāi)源
Kotlin 語(yǔ)言(包括編譯器、庫(kù)和所有相關(guān)工具)是完全開(kāi)源的,并且可以自由使用。 它采用 Apache 2 許可證 ;其開(kāi)發(fā)過(guò)程完全公開(kāi)在 GitHub (http://github.com/jetbrains/ kotlin) 上,并且歡迎來(lái)自社區(qū)的貢獻(xiàn)。如果你要開(kāi)發(fā) Kotlin 應(yīng)用程序,有三種開(kāi)源 IDE 供你選擇 :IntelliJ IDEA Community2 版、Android Studio 以及 Eclipse,它們都完 全支持 Kotlin(當(dāng)然,IntelliJ IDEA Ultimate 也支持 Kotlin。)
現(xiàn)在你明白了 Kotlin 是什么語(yǔ)言,讓我們看看 Kotlin 在具體的實(shí)際應(yīng)用中會(huì)給你帶來(lái)哪些好處。

如前所述,Kotlin 使用的兩個(gè)主要的領(lǐng)域是服務(wù)器端和 Android 開(kāi)發(fā)。接下來(lái) 我們分別看看這兩個(gè)領(lǐng)域,以及為什么 Kotlin 非常適合它們。
服務(wù)器端的 Kotlin
服務(wù)器端編程是一個(gè)非常大的概念,它包含了所有下列的應(yīng)用程序類(lèi)型甚至更多 :
返回 HTML 頁(yè)面給瀏覽器的 Web 應(yīng)用程序
通過(guò) HTTP 暴露 JSON API 的移動(dòng)應(yīng)用后端服務(wù)
通過(guò) RPC 協(xié)議互相通信的微服務(wù)
多年以來(lái),開(kāi)發(fā)者一直在構(gòu)建這些類(lèi)型的應(yīng)用,并且積累了大量的框架和技術(shù) 來(lái)幫助他們構(gòu)建這些應(yīng)用。這些應(yīng)用通常并不是孤立地開(kāi)發(fā)或者從零開(kāi)始的,它們 幾乎總是對(duì)現(xiàn)有的系統(tǒng)進(jìn)行擴(kuò)展、改進(jìn)或者替換,新的代碼必須和系統(tǒng)中現(xiàn)有部分 進(jìn)行集成,而這些部分可能很多年之前就寫(xiě)成了。
這種環(huán)境下 Kotlin 的一大優(yōu)勢(shì)就是它與現(xiàn)有的 Java 代碼無(wú)縫的互操作性。無(wú)論 是要編寫(xiě)一個(gè)全新的組件還是移植一個(gè)現(xiàn)有服務(wù)的代碼,Kotlin 都毫無(wú)壓力。不管 你需要在 Kotlin 中繼承 Java 類(lèi),還是以某種方式注解一個(gè)類(lèi)的方法或字段,都不會(huì) 遇到任何問(wèn)題。它帶來(lái)的優(yōu)點(diǎn)是系統(tǒng)的代碼會(huì)更緊湊、更可靠、更易于維護(hù)。
與此同時(shí),Kotlin 還引入了許多用于開(kāi)發(fā)這類(lèi)系統(tǒng)的新技術(shù)。例如,對(duì)構(gòu)建器 模式的支持讓你可以使用更簡(jiǎn)潔的語(yǔ)法來(lái)創(chuàng)建任何對(duì)象圖,同時(shí)保留了語(yǔ)言中全套 的抽象機(jī)制和代碼重用工具。
這個(gè)特性的一個(gè)簡(jiǎn)單的用例就是 HTML 生成庫(kù),它可以把一個(gè)外部模板語(yǔ)言 替換成簡(jiǎn)潔且完全類(lèi)型安全的解決方案。這里有一個(gè)例子 :
可以輕松地把映射到HTML標(biāo)簽的函數(shù)和常規(guī)的Kotlin語(yǔ)言結(jié)構(gòu)組合起來(lái)。你不再需要使用一門(mén)獨(dú)立的模板語(yǔ)言,也不需要學(xué)習(xí)新的語(yǔ)法,僅僅使用循環(huán)就可以生成HTML頁(yè)面。
另一個(gè)能用上Kotlin干凈和簡(jiǎn)潔的DSL的用例是持久化框架。例如,Exposed 框架(https://github.com/jetbrains/exposed)就提供了易讀的 DSL,可以完全使用 Kotlin 代碼來(lái)描述 SQL 數(shù)據(jù)庫(kù)的結(jié)構(gòu)并執(zhí)行查詢(xún)操作,并且有全面的類(lèi)型檢查。下 面這個(gè)小例子展示了可行的做法 :
Android 上的 Kotlin
一個(gè)典型的移動(dòng)應(yīng)用和一個(gè)典型的企業(yè)應(yīng)用完全不同。它更小,更少地依賴(lài)與 現(xiàn)有的代碼集成,通常需要快速交付,同時(shí)需要保證在大量的設(shè)備上能夠可靠地運(yùn) 行。這類(lèi)項(xiàng)目 Kotlin 也能勝任。
Kotlin 的語(yǔ)言特性,加上支持 Android 框架的特殊編譯器插件,讓 Android 的 開(kāi)發(fā)體驗(yàn)變得高效和愉悅。常見(jiàn)的開(kāi)發(fā)任務(wù),比如給控件添加監(jiān)聽(tīng)器或是把布局元 素綁定到字段,可以用更少的代碼完成,有時(shí)甚至根本不用寫(xiě)任何代碼(編譯器會(huì)幫你生成)。同樣由 Kotlin 團(tuán)隊(duì)打造的庫(kù) Anko(https://github.com/kotlin/anko)給許多標(biāo)準(zhǔn) Android API 添加了 Kotlin 友好的適配器,進(jìn)一步提升了 Android 的開(kāi)發(fā)體驗(yàn)。
下面是 Anko 的一個(gè)簡(jiǎn)單例子,可以品嘗到使用 Kotlin 進(jìn)行 Android 開(kāi)發(fā)的滋味。只要把這段代碼放在一個(gè) Activity 中,一個(gè)簡(jiǎn)單的 Android 應(yīng)用就做好了!
使用Kotlin帶來(lái)的另一優(yōu)勢(shì)就是更好的應(yīng)用可靠性。如果你有開(kāi)發(fā)Android應(yīng)用的經(jīng)驗(yàn),你一定對(duì)“Unfortunately, Process Has Stopped”對(duì)話框深?lèi)和唇^。如果你的應(yīng)用有未處理的異常,這個(gè)對(duì)話框就會(huì)出現(xiàn),而這種異常一般是NullPointerException(空指針異常)。Kotlin的類(lèi)型系統(tǒng)通過(guò)精確地跟蹤null值,大大減輕了空指針異常問(wèn)題帶來(lái)的壓力。大部分Java中會(huì)導(dǎo)致NullPointerException的代碼在Kotlin中無(wú)法編譯成功,以確保這些錯(cuò)誤在應(yīng)用到達(dá)用戶(hù)手中之前得到修正。
同時(shí),由于 Kotlin 完全兼容 Java 6,使用它并不會(huì)帶來(lái)任何新的編譯問(wèn)題。你 可以享受所有 Kotlin 的酷炫新特性,而你的用戶(hù)仍然可以在他們的設(shè)備上使用你的 應(yīng)用,即使他們的設(shè)備并沒(méi)有運(yùn)行新版本的 Android 系統(tǒng)。
說(shuō)到性能,Kotlin 也沒(méi)有帶來(lái)任何負(fù)面影響。Kotlin 編譯器生成的代碼執(zhí)行起 來(lái)和普通的 Java 代碼效率一樣。Kotlin 使用的運(yùn)行時(shí)(庫(kù))體積相當(dāng)小,所以編譯 出來(lái)的應(yīng)用程序包體積也不會(huì)增加多少。當(dāng)你使用 lambda 的時(shí)候,它們會(huì)被許多 Kotlin 標(biāo)準(zhǔn)庫(kù)函數(shù)內(nèi)聯(lián)。lambda 的內(nèi)聯(lián)確保不會(huì)創(chuàng)建新對(duì)象,因此應(yīng)用程序也不必 忍受額外的 GC 暫停。
看過(guò)了和 Java 相比 Kotlin 的優(yōu)勢(shì)之后,我們?cè)賮?lái)看看 Kotlin 的設(shè)計(jì)哲學(xué)——那 些把 Kotlin 和其他面向 JVM 的現(xiàn)代語(yǔ)言區(qū)分開(kāi)的主要特性。

當(dāng)談起 Kotlin 的時(shí)候,我們喜歡說(shuō)它是一門(mén)務(wù)實(shí)、簡(jiǎn)潔和安全的語(yǔ)言,專(zhuān)注于 互操作性。這里的每個(gè)詞語(yǔ)究是什么含義?我們逐個(gè)來(lái)看看。
務(wù)實(shí)
務(wù)實(shí)對(duì)我們來(lái)說(shuō)意味著一件簡(jiǎn)單的事情 :Kotlin 就是一門(mén)設(shè)計(jì)出來(lái)解決現(xiàn)實(shí)世界問(wèn)題的實(shí)用語(yǔ)言。它的設(shè)計(jì)基于多年創(chuàng)建大型系統(tǒng)的工業(yè)經(jīng)驗(yàn),它的特性也是為解決許多軟件開(kāi)發(fā)者遇到的場(chǎng)景而選擇的。此外,來(lái)自 JetBrains 內(nèi)部和社區(qū)的開(kāi)發(fā)者已經(jīng)使用 Kotlin 的早期版本很多年,他們的反饋也被融合進(jìn)了這門(mén)語(yǔ)言公開(kāi)發(fā)布的版本中。所以我們才能自信地說(shuō),Kotlin 能夠幫助解決實(shí)際項(xiàng)目的問(wèn)題。
Kotlin 也不是一門(mén)研究性的語(yǔ)言。我們沒(méi)有試圖提升編程語(yǔ)言設(shè)計(jì)領(lǐng)域目前的技術(shù)水平,也沒(méi)有嘗試探索計(jì)算機(jī)科學(xué)的創(chuàng)新理念。反而,我們會(huì)盡可能地依賴(lài)已經(jīng)出現(xiàn)在其他編程語(yǔ)言中并被證明是成功的那些特性和解決方案。這降低了語(yǔ)言的復(fù)雜性,也讓它更容易學(xué)習(xí),因?yàn)槟憧梢匝稣棠切┦煜さ母拍睢?/span>
此外,Kotlin 也沒(méi)有強(qiáng)制使用某種特定的編程風(fēng)格和范式。當(dāng)你開(kāi)始學(xué)習(xí)這門(mén)語(yǔ)言的時(shí)候,可以使用熟悉的來(lái)自 Java 經(jīng)驗(yàn)的風(fēng)格。然后,你會(huì)漸漸地發(fā)現(xiàn)更多強(qiáng)大的 Kotlin 特性,并學(xué)習(xí)把它們應(yīng)用到你的代碼中,讓代碼更簡(jiǎn)潔、更符合語(yǔ)言習(xí)慣。
Kotlin 的實(shí)用主義的另一個(gè)重要體現(xiàn)是對(duì)于工具的專(zhuān)注。對(duì)開(kāi)發(fā)者的生產(chǎn)力而言,一個(gè)智能的開(kāi)發(fā)環(huán)境和一門(mén)設(shè)計(jì)良好的語(yǔ)言同樣重要。因此,事后再來(lái)考慮對(duì) IDE 進(jìn)行支持就是馬后炮。而 Kotlin 的情況是,IntelliJ IDEA 的插件是和編譯器同步開(kāi)發(fā)的,并且在設(shè)計(jì)語(yǔ)言特性時(shí)始終牢記著對(duì)工具的支持。
IDE 支持對(duì)幫助你探索 Kotlin 的特性也發(fā)揮著重要作用。許多情況下,工具會(huì)發(fā)現(xiàn)那些可以用更簡(jiǎn)潔的結(jié)構(gòu)來(lái)替換的通用代碼模式,并給你提供修正這些代碼的選擇。通過(guò)研究自動(dòng)修正所使用的語(yǔ)言特性,你就能學(xué)習(xí)如何在自己的代碼中應(yīng)用這些特性。
簡(jiǎn)潔
和編寫(xiě)新代碼相比,開(kāi)發(fā)人員會(huì)耗費(fèi)更多的時(shí)間來(lái)閱讀現(xiàn)有代碼,這已經(jīng)是常識(shí)。想象一下你所在的團(tuán)隊(duì)正在開(kāi)發(fā)一個(gè)大項(xiàng)目,而你的工作是添加一個(gè)新特性或者修改 bug。步會(huì)干什么?首先要找到需要改變的那段代碼,然后才能實(shí)現(xiàn)你的修改。要閱讀很多代碼才能知道你要做什么。這些代碼可能近剛完成,由你的同事或者是那些已經(jīng)離開(kāi)的同事編寫(xiě),或者是你自己很久之前寫(xiě)好的。只有搞懂了周?chē)拇a你才能做出正確的改動(dòng)。
代碼越簡(jiǎn)單越簡(jiǎn)潔,你就能越快地了解發(fā)生了什么。當(dāng)然,良好的設(shè)計(jì)和達(dá)意的命名在這里起著重要的作用。但語(yǔ)言的選擇及其簡(jiǎn)潔性也很重要。如果語(yǔ)言的語(yǔ)法清晰地表達(dá)了被閱讀的代碼的意圖,沒(méi)有因?yàn)檫_(dá)成意圖所需的樣板代碼而晦澀難懂,那么它就是簡(jiǎn)潔的。
在 Kotlin 中,我們努力地保證你寫(xiě)的代碼都具有實(shí)際的意義,而不是僅僅為了滿足代碼結(jié)構(gòu)的需要。許多標(biāo)準(zhǔn)的 Java 樣板代碼,例如 getter、setter 以及將構(gòu)造方法的參數(shù)賦值給字段的邏輯,在 Kotlin 中都是隱式的,并不會(huì)使你的源代碼變得混亂。
另外一個(gè)導(dǎo)致代碼變得不必要的冗長(zhǎng)的原因是編寫(xiě)顯式的代碼來(lái)完成常見(jiàn)的任務(wù),比如定位集合中的元素。和許多其他現(xiàn)代語(yǔ)言一樣,Kotlin 有豐富的標(biāo)準(zhǔn)庫(kù),讓你用庫(kù)方法調(diào)用來(lái)代替這些冗長(zhǎng)重復(fù)的代碼段。Kotlin 對(duì) lambda 的支持,讓小代碼塊可以輕松地傳遞給庫(kù)函數(shù)。這讓你可以把公共的那部分代碼全部封裝在庫(kù)中,而在用戶(hù)代碼中僅保留特定的針對(duì)任務(wù)的那部分。
與此同時(shí),Kotlin 并沒(méi)有嘗試把源代碼壓縮到小可能的長(zhǎng)度。例如,即使 Kotlin 支持運(yùn)算符重載,用戶(hù)也不能定義自己的運(yùn)算符。因此,庫(kù)開(kāi)發(fā)者不能用神秘的標(biāo)點(diǎn)符號(hào)序列來(lái)代替方法名字。單詞比標(biāo)點(diǎn)符號(hào)顯然更易讀,也更容易找到相關(guān)的文檔。
越簡(jiǎn)潔的代碼寫(xiě)起來(lái)花的時(shí)間越短,更重要的是,讀起來(lái)耗費(fèi)的時(shí)間也更短。這會(huì)提高你的生產(chǎn)力并讓你更快地達(dá)成目標(biāo)。
安全
通常,我們說(shuō)一門(mén)編程語(yǔ)言是安全的,我們的意思是它的設(shè)計(jì)可以防止程序出現(xiàn)某些類(lèi)型的錯(cuò)誤。當(dāng)然,這并不意味著絕對(duì)的高質(zhì)量,沒(méi)有任何語(yǔ)言可以阻止所有可能出現(xiàn)的錯(cuò)誤。此外,預(yù)防錯(cuò)誤是需要成本的。需要給編譯器提供程序有關(guān)預(yù)期操作更多的信息,這樣編譯器才能驗(yàn)證這些信息是否和程序的功能匹配。因此,你要在得到的安全級(jí)別和因?yàn)樵黾痈嗉?xì)節(jié)注解而造成的生產(chǎn)力損失之間權(quán)衡利弊。
使用 Kotlin,我們?cè)噲D實(shí)現(xiàn)比 Java 更高的安全級(jí)別,同時(shí)保持更低的總體成本。在 JVM 上運(yùn)行已經(jīng)提供了許多的安全保證 :例如,內(nèi)存安全,防止了緩沖區(qū)溢出以及其他錯(cuò)誤的動(dòng)態(tài)內(nèi)存分配造成的問(wèn)題。作為面向 JVM 的靜態(tài)類(lèi)型語(yǔ)言,Kotlin 還保證了應(yīng)用程序的類(lèi)型安全。這比使用 Java 的成本要更低 :不需要指定所有的類(lèi)型聲明,因?yàn)樵S多情況下編譯器會(huì)自動(dòng)地推斷出類(lèi)型。
Kotlin 所做的不止這 些,這意味著更多的原本在運(yùn)行時(shí)失敗的錯(cuò)誤在編譯期的檢查中就被阻止 了。重要的一點(diǎn)是,Kotlin 努力地從你的程序中消除 NullPointerException。Kotlin 的類(lèi)型系統(tǒng)跟蹤那些可以或不可以為 null 的值,并且禁止那些運(yùn)行時(shí)可能導(dǎo)致 NullPointerException 的操作。這所帶來(lái)的額外的成本是極小的 :把類(lèi)型標(biāo)記為可空的只要一個(gè)字符,就是類(lèi)型尾部的一個(gè)問(wèn)號(hào) :
除此之外,Kotlin 提供了許多便利的方法來(lái)處理可空數(shù)據(jù)。這非常有助于消滅應(yīng)用程序的崩潰。
Kotlin 有助于避免的另一種異常類(lèi)型就是 ClassCastException。當(dāng)你把一 個(gè)對(duì)象轉(zhuǎn)換成一種類(lèi)型,而沒(méi)有事先檢查它是否是正確的類(lèi)型時(shí),就會(huì)發(fā)生這個(gè)異 常。在 Java 中,開(kāi)發(fā)者常常省略了這類(lèi)檢查,因?yàn)楸仨毞磸?fù)地在檢查和其后的轉(zhuǎn)換 中寫(xiě)明類(lèi)型名稱(chēng)。另一方面,Kotlin 中的檢查和轉(zhuǎn)換被組合成了一次操作 :一旦檢 查過(guò)類(lèi)型,不需要額外的轉(zhuǎn)換就能直接引用屬于這個(gè)類(lèi)型的成員。這樣,開(kāi)發(fā)者就 沒(méi)有借口跳過(guò)檢查,也不會(huì)給錯(cuò)誤留下可乘之機(jī)。下面展示了它是如何工作的 :
互操作性
關(guān)于互操作 性,你的個(gè)問(wèn)題可能是 :“我是不是可以繼續(xù)使用現(xiàn)有的 庫(kù)?”Kotlin 給出的回答是 :“當(dāng)然可以。”無(wú)論需要使用哪種庫(kù)提供的 API,都可 以在 Kotlin 中使用它們。可以調(diào)用 Java 的方法,繼承 Java 的類(lèi)和實(shí)現(xiàn) Java 的接口, 在 Kotlin 類(lèi)上應(yīng)用 Java 的注解,等等。
與其他一些 JVM 語(yǔ)言不同,Kotlin 在互操作性上更上一層樓,讓 Java 代碼也 可以毫不費(fèi)力地調(diào)用 Kotlin 的代碼。無(wú)須取巧 :Kotlin 的類(lèi)和方法可以像常規(guī)的 Java 類(lèi)和方法一樣被調(diào)用。這帶來(lái)了無(wú)限的靈活性,在項(xiàng)目的任何地方都可以混合 使用 Java 和 Kotlin。當(dāng)你剛開(kāi)始在自己的 Java 項(xiàng)目中引入 Kotlin 時(shí),可以在代碼庫(kù) 中的任意一個(gè)類(lèi)上運(yùn)行 Java 到 Kotlin 的轉(zhuǎn)換器,剩下的代碼不需要任何修改就可以 繼續(xù)編譯和工作。不管你所轉(zhuǎn)換的類(lèi)是什么角色,這都是可行的。
另一個(gè) Kotlin 專(zhuān)注于互操作性的領(lǐng)域是在大程度上使用現(xiàn)有的 Java 庫(kù)。例如, Kotlin 沒(méi)有自己的集合庫(kù),它完全依賴(lài) Java 標(biāo)準(zhǔn)庫(kù)中的類(lèi),使用額外的函數(shù)來(lái)擴(kuò)展 它們,讓它們?cè)?Kotlin 中用起來(lái)更方便(我們會(huì)在 3.3 節(jié)中了解這種機(jī)制更多的細(xì)節(jié))。 這意味著在 Kotlin 中調(diào)用 Java API 時(shí),永遠(yuǎn)不需要包裝或者轉(zhuǎn)換這些 Java 對(duì)象,反 之亦然。所有這些 Kotlin 提供的豐富的 API 在運(yùn)行時(shí)沒(méi)有任何的額外開(kāi)銷(xiāo)。
Kotlin 工具也對(duì)跨語(yǔ)言項(xiàng)目提供了全面支持。它可以編譯任意混合的 Java 和 Kotlin 源碼,不管它們之間是怎樣互相依賴(lài)的。IDE 的特性也能跨語(yǔ)言工作,允許 :
自由地在 Java 和 Kotlin 源碼文件之間切換
調(diào)試混合語(yǔ)言的項(xiàng)目,可以在不同語(yǔ)言編寫(xiě)的代碼之中單步調(diào)試
重構(gòu) Java 方法的時(shí)候,Kotlin 代碼中的對(duì)它們的調(diào)用也會(huì)得到正確的更新,反之亦然
希望我們已經(jīng)說(shuō)服你嘗試一下 Kotlin。現(xiàn)在,你要如何開(kāi)始使用它?在接下來(lái) 的一節(jié)中,我們將從命令行和其他不同工具的使用兩方面討論編譯和運(yùn)行 Kotlin 代 碼的過(guò)程。

和 Java 一樣,Kotlin 也是編譯型語(yǔ)言。這意味著你必須先編譯,然后才能執(zhí)行 Kotlin 代碼。讓我們來(lái)討論一下編譯過(guò)程,然后看看幫你完成這個(gè)過(guò)程需要的不同工具。如果你需要關(guān)于如何搭建開(kāi)發(fā)環(huán)境的信息,請(qǐng)參考 Kotlin 官方網(wǎng)站的“Tutorials”(教程)一節(jié) (https://kotlinlang.org/docs/tutorials)。
編譯 Kotlin 代碼
Kotlin 的源代碼存放在后綴名為 .kt 的文件中。Kotlin 編譯器會(huì)分析源代碼并生成 .class 文件,這和 Java 編譯器做的沒(méi)什么不同。然后按照你正在處理的應(yīng)用程序類(lèi)型的標(biāo)準(zhǔn)過(guò)程打包和執(zhí)行生成的 .class 文件。簡(jiǎn)單的情況下,只需要使用 kotlinc 命令就可以從命令行編譯代碼,然后就可以用 java 命令執(zhí)行你的代碼 :
kotlinc <source file or directory> -include-runtime -d <jar name>java -jar <jar name>
圖1.1展示了Kotlin構(gòu)建過(guò)程的簡(jiǎn)單描述。
圖 1.1 Kotlin 構(gòu)建過(guò)程
用 Kotlin 編譯器編譯的代碼依賴(lài) Kotlin 運(yùn)行時(shí)庫(kù)。它包括了 Kotlin 自己的標(biāo)準(zhǔn) 庫(kù)類(lèi)的定義,以及 Kotlin 對(duì)標(biāo)準(zhǔn) Java API 的擴(kuò)展。運(yùn)行時(shí)庫(kù)需要和你的應(yīng)用程序一 起分發(fā)。
在大多數(shù)實(shí)際工作的例子中,你會(huì)使用像 Maven、Gradle 或者 Ant 這樣的構(gòu)建系統(tǒng)來(lái)編譯你的代碼。Kotlin 和所有這些構(gòu)建系統(tǒng)都兼容,我們會(huì)在附錄 A 中討論相關(guān)細(xì)節(jié)。所有這些構(gòu)建系統(tǒng)也支持在同一個(gè)代碼庫(kù)中既有 Kotlin 也有 Java 的混合語(yǔ)言項(xiàng)目。此外,Maven 和 Gradle 還會(huì)幫你把 Kotlin 運(yùn)行時(shí)庫(kù)作為依賴(lài)加入到你的應(yīng)用程序中。
IntelliJ IDEA 和 Android Studio 插件
IntelliJ IDEA 的 Kotlin 插件是和語(yǔ)言同步開(kāi)發(fā)的,它是 Kotlin 可用的功能全面的開(kāi)發(fā)環(huán)境。它成熟且穩(wěn)定,提供了 Kotlin 開(kāi)發(fā)所需的全套工具。
IntelliJ IDEA 15 及 其后 續(xù)版 本不 需 要額 外的 設(shè) 置,Kotlin 插 件就可以開(kāi)箱即用。可以選擇免費(fèi)開(kāi)源的 IntelliJ IDEA Community 版,也可以選擇 IntelliJ IDEA Ultimate。在“New Project”(新建項(xiàng)目)對(duì)話框中選擇“Kotlin”,然后就可以開(kāi)始工作了。
如果你用的是 Android Studio,可以從“plug-in manager”(插件管理器)中安裝 Kotlin 插件。打開(kāi)“Settings”(設(shè)置)對(duì)話框,選擇“Plugins”(插件),單擊“Install JetBrains Plugin”(安裝 JetBrains 插件)按鈕,然后從列表中選擇“Kotlin”。
交互式 shell
如果你想快速地嘗試小段的 Kotlin 代碼,可以使用交互式 shell( 也叫 REPL3 )。 在 REPL 中,可以逐行地輸入 Kotlin 代碼并立即看到其執(zhí)行結(jié)果,可以使用不帶任 何參數(shù)的 kotlinc 命令啟動(dòng) REPL,也可以從 IntelliJ IDEA 的“Kotlin”菜單中選 擇啟動(dòng) REPL。
Eclipse 插件
如果你是 Eclipse 用 戶(hù),同樣可以選擇在你的 IDE 中使用 Kotlin。Kotlin 的 Eclipse 插件提供了必要的 IDE 功能,如導(dǎo)航和代碼補(bǔ)全。該插件可以在 Eclipse Marketplace 中找到。要安裝它,請(qǐng)選擇“Help > Eclipse Marketplace”菜單項(xiàng),然后在列表中搜索“Kotlin”。
在線 playground
嘗試 Kotlin 的簡(jiǎn)單的方式,是不需要任何安裝和配置。可以在 http://try.kotl.in 找到在線的 playground,可以在上面編寫(xiě)、編譯及運(yùn)行 Kotlin 的小程序。Playground 上還展示了 Kotlin 特性的代碼示例,其中包括了本書(shū)中的所有例子,還有一系列交互式學(xué)習(xí) Kotlin 的練習(xí)。
Java 到 Kotlin 的轉(zhuǎn)換器
要熟練掌握一門(mén)新語(yǔ)言總是要費(fèi)點(diǎn)力氣的。幸運(yùn)的是,我們開(kāi)辟了一條很棒的小捷徑,讓你可以借助現(xiàn)有的 Java 知識(shí)來(lái)加快學(xué)習(xí)和運(yùn)用 Kotlin 的速度。這個(gè)工具就是 Java 到 Kotlin 的自動(dòng)轉(zhuǎn)換器。
當(dāng)你開(kāi)始學(xué)習(xí) Kotlin 的時(shí)候,如果你還沒(méi)有記住準(zhǔn)確的語(yǔ)法,轉(zhuǎn)換器能幫你表達(dá)一些內(nèi)容。可以先用 Java 寫(xiě)出相應(yīng)的代碼片段,然后把它粘貼到 Kotlin 文件中,轉(zhuǎn)換器會(huì)自動(dòng)地將代碼轉(zhuǎn)換成 Kotlin。轉(zhuǎn)換的結(jié)果不一定總是符合語(yǔ)言習(xí)慣,但是它一定是可以工作的代碼,這樣就可以讓你的任務(wù)更進(jìn)一步了。
在現(xiàn)有的 Java 項(xiàng)目中引入 Kotlin 時(shí),轉(zhuǎn)換器也很好用。當(dāng)你寫(xiě)一個(gè)新類(lèi)時(shí),可以從一開(kāi)始就用 Kotlin。但是如果你要在一個(gè)現(xiàn)有的類(lèi)上做重大的更改時(shí),可能也想在這個(gè)過(guò)程中使用 Kotlin,這時(shí)轉(zhuǎn)換器就派上用場(chǎng)了。首先把這個(gè)類(lèi)轉(zhuǎn)換成 Kotlin,然后就可以利用現(xiàn)代編程語(yǔ)言的所有優(yōu)勢(shì)來(lái)添加更改了。
在 IntelliJ IDEA 中使用轉(zhuǎn)換器再簡(jiǎn)單不過(guò)了。要么復(fù)制一段 Java 代碼粘貼到 Kotlin 文件中,要么觸發(fā)“Convert Java File to Kotlin File”(轉(zhuǎn)換 Java 文件到 Kotlin 文件)動(dòng)作來(lái)轉(zhuǎn)換整個(gè)文件。也可以在 Eclipse 中或者線上使用轉(zhuǎn)換器。

Kotlin 是靜態(tài)類(lèi)型語(yǔ)言并支持類(lèi)型推導(dǎo),允許維護(hù)正確性與性能的同時(shí)保持源代碼的簡(jiǎn)潔。
Kotlin 支持面向?qū)ο蠛秃瘮?shù)式兩種編程風(fēng)格,通過(guò)頭等函數(shù)使更高級(jí)別的抽象成為可能,通過(guò)支持不可變值簡(jiǎn)化了測(cè)試和多線程開(kāi)發(fā)。
在服務(wù)器端應(yīng)用程序中它工作得很好,全面支持所有現(xiàn)存的 Java 框架,為常見(jiàn)的任務(wù)提供了新工具,如生成 HTML 和持久化。
在 Android 上它也可以工作,這得益于緊湊的運(yùn)行時(shí)、對(duì) Android API 特殊的編譯器支持以及豐富的庫(kù),為常見(jiàn) Android 開(kāi)發(fā)任務(wù)提供了 Kotlin 友好的 函數(shù)。
它是免費(fèi)和開(kāi)源的,全面支持主流的 IDE 和構(gòu)建系統(tǒng)。
Kotlin 是務(wù)實(shí)的、安全的、簡(jiǎn)潔的,與 Java 可互操作,意味著它專(zhuān)注于使用已經(jīng)證明過(guò)的解決方案處理常見(jiàn)任務(wù),防止常見(jiàn)的像 NullPointerException 這樣的錯(cuò)誤,支持緊湊和易讀的代碼,以及提供與 Java 無(wú)限制的集成。
本站文章版權(quán)歸原作者及原出處所有 。內(nèi)容為作者個(gè)人觀點(diǎn), 并不代表本站贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé),本站只提供參考并不構(gòu)成任何投資及應(yīng)用建議。本站是一個(gè)個(gè)人學(xué)習(xí)交流的平臺(tái),網(wǎng)站上部分文章為轉(zhuǎn)載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對(duì)作者和來(lái)源進(jìn)行了通告,但是能力有限或疏忽,造成漏登,請(qǐng)及時(shí)聯(lián)系我們,我們將根據(jù)著作權(quán)人的要求,立即更正或者刪除有關(guān)內(nèi)容。本站擁有對(duì)此聲明的最終解釋權(quán)。