天天看點

帶你讀《Kotlin核心程式設計》之一:認識Kotlin第1章

點選檢視第二章 點選檢視第三章

Kotlin核心程式設計

帶你讀《Kotlin核心程式設計》之一:認識Kotlin第1章

水滴技術團隊 著

第1章

認識Kotlin

在Java之後,JVM平台上出現了其他的程式設計語言,Scala和Kotlin可以算是其中的佼佼者。Scala已成為大資料領域的明星,而Kotlin在2017年Google I/O大會之後,也成為安卓平台上潛力巨大的官方支援語言。它們都因被冠以“更好的Java”而為人稱道,然而它們采用的卻是兩種不同的設計理念。

本章我們通過對比Java、Scala、Kotlin這3種程式設計語言各自的發展路線,來認識Kotlin的設計哲學。

1.1 Java的發展

不得不說,Java是當今最成功的程式設計語言之一。自1996年問世,Java就始終占據着程式設計語言生态中很大的份額。它的優勢主要展現在:

  • 多平台與強大的社群支援。無論是用于Web開發還是用于移動裝置,Java都是主流的程式設計語言之一。
  • 尊重标準。它有着嚴格的語言規範及向後相容性,是以非常适合開發團隊之間的協作,即使組織變動,新人同樣可以在相同的規範下快速參與項目開發。

然而,随着計算平台的快速發展,平台和業務本身對程式設計語言提出了更大的挑戰。Java的發展也受到環境變化所帶來的影響。一方面,多核時代與大資料的到來,使得古老的函數式程式設計又重新變得“時髦”,Scala、Clojure這種多範式的程式設計語言開始受到越來越多開發人員的關注和喜愛;另一方面,Java的嚴格規範也常常引發抱怨。

是以,Java必須開始改變。

1.1.1 Java 8的探索

如果說Java 5引入泛型是Java發展曆史上重大的進步,那麼Java 8的釋出也同樣意義深遠,它是Java對其未來發展的一次嶄新探索。Java 8引入了很多全新的語言特性,如:

  • 高階函數和Lambda。首次突破了隻有類作為“頭等公民”的設計,支援将函數作為參數來進行傳遞,同時結合Lambda文法,改變了現有的程式設計模式。
  • Stream API。流的引入簡化了日常開發中的集合操作,賦予了Java更強大的業務表達能力,并增強了代碼的可讀性。
  • Optional類。它為消除null引用所帶來的NullPointerException問題,在類型層面提供了一種解決思路。

這一次的釋出在Java社群引起了不同尋常的反響,因為Java程式員開始感受到另外一種程式設計範式所帶來的全新體驗,也就是所謂的函數式程式設計。擁抱函數式也為Java的發展指出了一個很好的方向。

1.1.2 Java未來的樣子

2016年11月,在歐洲最大的Java峰會上,Oracle的Java語言架構師Brian Goetz分享了關于Java這門語言未來發展的演講。本次會議最大的收獲就是探索了未來Java可能支援的語言特性,它們包含:

  • 資料類。
  • 值類。
  • 泛型特化。
  • 更強大的類型推導。
  • 模式比對。

以上的語言特性對于初嘗函數式程式設計甜頭的Java開發者而言,是十分值得期待的。它們可以進一步解放Java,讓開發工作變得更加高效和靈活。比如,一旦Java支援了資料類,我們就可以用非常簡短的文法來表示一個常見的資料對象類,如下所示:

public class User(String firstName, String lastName, DateTime birthday)

而若用如今的JavaBean,則意味着好幾倍的代碼量,這一切都讓人迫不及待。與此同時,或許早有Java程式員開始了JVM平台上另一種語言的研究。這門語言已支援了所有這些新的特性,并在設計之初就內建了面向對象和函數式兩大特征,它就是Scala。

1.2 Scala的百寶箱

Scala是洛桑聯邦理工大學的馬丁(Martin Odersky)教授創造的一門語言。他也參與了Java語言的發展研究工作,在Java 5中引入的泛型就是他的傑作。事實上,在Java剛釋出的時候,馬丁教授就開始了Java的改良工作—他在JVM平台探索函數式程式設計,并釋出了一個名為Pizza的語言,那時就支援了泛型、高階函數和模式比對。

然而,在随後的探索過程中,他漸漸發現Java是一門具有硬性限制的語言,在某些時候不能采用最優的方式來實施設計方案。是以,馬丁教授和他的研究夥伴決定重新創造一門語言,既在學術上合理,同時也具備實用價值。這就是開發Scala的初衷。

1.2.1 學術和工業的平衡

Scala是一門非常強大的程式設計語言,正如它名字(Scalable,可拓展)本身一樣,用Scala程式設計就像擁有了哆啦A夢的口袋,裡面裝滿了各種程式設計語言特性,如面向對象、函數式、宏。

Scala不僅在面向對象方面進行了諸多的改良,而且徹底擁抱了函數式。是以Scala也吸引了函數式程式設計社群很多厲害的程式員,他們将函數式程式設計的思想注入Scala社群,如此将使用Scala進行函數式程式設計提高到了新的高度。

由于Scala設計者學院派的背景,以及Scala某些看似“不同尋常”的文法,使它在發展早期(甚至現在)經常被描述為“過于學院派”,以至于馬丁教授在某次Scala大會的演講時,自嘲“Scala真正的作用是将人引向了Haskell”。

然而,真實的Scala卻是在不斷地探索學術和實用價值兩方面的平衡。不可否認的是:

  • Scala已經成為大資料領域的熱門語言,明星項目Spark就是用Scala開發的,還有很多其他知名的項目,如Akka、Kafka等。
  • 越來越多的商業公司,如Twitter、PayPal、Salesforce都在大量使用這門語言。

另外,Scala也确實是一門有着較陡的學習曲線的語言,因為它強大且靈活,正如馬丁教授所言,Scala相信程式員的聰明才智,開發人員可以用它來靈活選擇語言特性。但學術和工業的平衡始終是一個難題,與Java嚴格标準相比,Scala的多重選擇也常常因複雜而被人吐槽。

1.2.2 複合但不複雜

那麼,Scala真的複雜嗎?我們不知聽了多少次類似這樣的抱怨。在搞明白這個問題之前,我們需要先弄清楚到底什麼是“複雜”。在英文中,複雜一詞可以聯想到兩個單詞:complex和complicated。實際上它們的含義截然不同,更準确地說,complex更好的翻譯是“具有複合性”。

Nicolas Perony曾在Ted上發表過一次關于“複合性理論”的演講。

什麼是複合性?複合并不是複雜。一件複雜的事物是由很多小部分組成的,每一部分都各不相同,而且每一部分都在這個體系中有其自身的确切作用。與之相反,一個複合的系統是由很多類似的部分所組成的,而且(就是因為)它們之間的互相影響形成了一種宏觀上一緻的行為。複合系統含有很多互動的元素,它們根據簡單的、個體的規則行動,如此導緻新特征的出現。

馬丁教授曾發表過一篇名為《簡單還是複雜》的文章,表達過類似的觀點。如果對搭積木這件事情進行思考,摩比世界提供了固定的方案,而樂高則提供了無窮的選擇。然而,前者的零件種類和數量都比後者要多得的。類似的道理,程式設計語言可以依靠功能累加來建構所謂的文法,同樣也可以通過簡單完備的理論來發展語言特性。在馬丁教授看來,Scala顯然屬于後者,它并不複雜,而且非常簡單。

1.2.3 簡單卻不容易

事實上,函數式程式設計最明顯的特征就是具備複合性。函數式開發做得最多的事情就是對需要處理的事物進行組合。如果說面向對象是歸納法,側重于對事物特征的提取及概括,那麼函數式中的組合思想則更像是演繹法,近似于數學中的推導。

“簡單”的哲學也帶來了相應的代價:

  • 這是一種更加抽象的程式設計範式,諸如高階類型、Typeclass等進階的函數式特性雖然提供了無比強大的抽象能力,但學習成本更高。
  • 它建立了另一種與采用Java面向對象程式設計截然不同的思維模式。這種思維方式上的巨大差異顯然是一個極高的門檻,同時也是造成Scala令人望而卻步的原因之一。

Scala在選擇徹底擁抱函數式的同時,也意味着它不是一門容易的語言,它無法成為一門像Java那樣主流的程式設計語言。事實上,即使很多人采用Scala來進行開發,也還是采用類似Java的思維模式來程式設計。換句話說,Scala依舊是被當作更好的Java來使用的,但這确實是當今主流程式設計界最大的訴求。

在這種背景下,Kotlin作為一門JVM平台上新興的程式設計語言,悄悄打開了一扇同樣廣闊的大門。

1.3 Kotlin—改良的Java

2010年,JetBrains産生創造Kotlin的想法。關于大名鼎鼎的JetBrains,想必在業内是人盡皆知,知名的IntelliJ IDEA就是他們的産品之一。擁有為各種語言建構開發工具經驗的JetBrains,自然是對程式設計語言設計領域最熟悉的一群人。當時,一方面他們看到了C#在.NET平台上大放異彩;另一方面,Java相比新語言在某種程度上的滞後,讓他們意識到改良Java這門主流語言的必要性。

JetBrains團隊設計Kotlin所要面臨的第一個問題,就是必須相容他們所擁有的數百萬行Java代碼庫,這也代表了Kotlin基于整個Java社群所承載的使命之一,即需要與現有的Java代碼完全相容。這個背景也決定了Kotlin的核心目标—為Java程式員提供一門更好的程式設計語言。

1.3.1 Kotlin的實用主義

Kotlin常常被認為是一門近似于Scala的語言。的确,它們的誕生都源于對Java語言的改良,同時都在面向對象和函數式之間建立起了多範式的橋梁。不可否認的是,Kotlin确實從Scala身上借鑒了許多,就連它的創作團隊也表示過:“如果你用Scala感到很開心,那麼你并不需要Kotlin。”

然而,Kotlin與Scala的設計哲學又十分不同。Kotlin并沒有像Scala那樣熱衷于程式設計語言本身的研究和探索。相反,它在解放Java的同時,又在語言特性的選擇上表現得相當克制。

我們說過,Scala旨在成為一門程式員夢想中的語言,它包含了所有你想擁有的語言特性。而Kotlin更加立足現實,它現階段仍沒有宏,也拒絕了很多所謂的進階函數式語言特性。但它在Java 的基礎上發展出很多改善生産力的語言特性,如資料類、when表達式(一定程度上的模式比對)、擴充函數(和屬性)、可空類型等,而且它似乎偏好文法糖,比如Smart Casts,因為這可以讓程式設計人員的工程開發變得更加容易。

可以看出,Kotlin的自我定位非常清晰,它的目标就是在計算機應用領域成為一門實用且高效的程式設計語言。如果說Scala的設計理念是more than Java(不僅僅是Java),那麼Kotlin才是一門真正意義上的better Java(更好的Java)。

1.3.2 更好的Java

如果你用Kotlin開發過業務,很快就會意識到它相較于Java的文法更加簡潔、高效。比如Kotlin做了這些改良:

  • 在很大程度上實作了類型推導,而Java在SE 10才支援了局部變量的推導。
  • 放棄了static關鍵字,但又引入了object,可以直接用它來聲明一個單例。而作為比較,Java則必須依靠建構所謂的“單例模式”才能等效表達。
  • 引入了一些在Java中沒有的“特殊類”,比如Data Classes(資料類)、Sealed Classes(密封類),我們可以建構更深程度上的代數資料類型,結合when表達式來使用。

但可能你會問,以上Kotlin的特性,Scala也有,能否可以說前者隻是後者的一個子集呢?這種表述其實是不恰當的。其實,Kotlin在緻力于成為更好的Java的道路上,不僅僅依靠這些新增的語言特性,它在相容Java方面做了大量的工作,比Scala走得更遠。

首先,從語言命名上就可以看出Kotlin在嚴格遵循Java的傳統,它們都采用了島嶼的名字。

Java的名字來源于印度尼西亞瓜哇島的英文名稱,而Kotlin是俄羅斯聖彼得堡附近的一個島嶼的名字。

其次,雖然都是相容Java,Scala(最近的幾個版本)必須要求Java 8,而Kotlin則可以與Java 6一起工作,這也是後者在Android上更加流行的原因之一。

另外,Kotlin并沒有像Scala那樣在文法的探索上表現得“随心所欲”,Java程式員在學習Kotlin新文法特性的同時,依舊可以保留更多原有的習慣。舉個例子,在Scala中,一切皆有類型。是以在大部分時間裡,我們都用等号來定義一個Scala的函數。函數體最後一個表達式的值就是這個函數的傳回類型。

def foo(x: Int) = {

val y = x + 2
x + y           

}

沒錯,Scala舍棄了return關鍵字。在Kotlin中,它也引入了使用單行表達式來定義函數的文法,不需要用return來傳回結果值。

fun foo(x: Int) = x

帶你讀《Kotlin核心程式設計》之一:認識Kotlin第1章

2 + 2

然而,大部分情況下,我們還是可以采用類似Java的方式來定義一個函數,如:

fun foo(x: Int): Int {

val y = x ![image.png](https://ucc.alicdn.com/pic/developer-ecology/f11b01d3e8224ee9a464f10a5587a339.png) 2
return y + 2           

由于Kotlin比Scala更加相容Java的生态和文法,Java程式員可以更加容易地掌握它。同時,Kotlin非常注重文法的簡潔表達。如果你了解Scala中的implicit,可能曾被這個Scala的文法驚吓到,因為它非常強大。然而,正如我們提到的,“簡單靈活”的另一面意味着抽象和晦澀。Kotlin注重的是工程的實用性,是以它創造了擴充的文法,雖然相比implicit在功能上有損失,但顯得更加具體直覺,且依舊非常強大,可滿足日常開發中絕大多數的需求。值得一提的是,Android則依靠這個Java所沒有的特性,推出了擴充庫android-ktx,我們在第7章将專門介紹這種強大的特性。

此外,Kotlin還新增了一些Java、Scala中沒有的文法糖。如果你從事Android開發,那麼肯定少不了在工程中寫過如下的Java代碼:

if(parentView instanceof ViewGroup){

((ViewGroup) parentView).addView(childView);           

為了類型安全,我們不得不寫兩遍ViewGroup。然而在Kotlin中我們卻可以直接這麼寫:

if(parentView is ViewGroup){

parentView.addView(childView)           

這依靠的是Kotlin中的Smart Casts特性。我們不評價這種文法糖是好是壞,但它可以在一定程度上改善我們在工程開發中的體驗。

總體而言,Kotlin旨在成為一門提升Java生産力的更好的程式設計語言,它擁有簡潔的表達能力、強大的工具支援,同時至今仍然保持着非常快速的編譯能力。相較而言,用Scala開發則常常受到編譯過慢帶來的困擾。

1.3.3 強大的生态

現在,我們已經了解了Kotlin整體的設計哲學,以及它相較Java、Scala的魅力所在。當然,本章似乎并沒有涉及任何文法細節,我們會在後續的内容中深入介紹Kotlin的語言特性,并且探索它具體的進階應用。

關于Kotlin,還有一個問題需要解答:我們究竟可以用它來做什麼?大機率上你是因為Kotlin成為Android官方支援語言的新聞而知曉它的。事實上,Kotlin不僅支援Android,它還是一門通用語言,如果用一句話來總結,那就是“Targeting JVM / JavaScript and Native”。現階段,我們至少可以用Kotlin做以下的事情。

(1)Android開發

我們不僅可以用Kotlin調用現成的Java庫,而且還有Google提供的Kotlin擴充庫。Kotlin的文法非常适合Android工程開發,例如我們提到過的Smart Casts。用它還可以改善findViewById的文法調用。

(2)服務端開發

這是JVM語言最大的一個應用領域,自然也是Kotlin發揮的舞台。在Android支援Kotlin之後,Spring Framework 5也對它敞開了懷抱。基于Kotlin更自然的函數式特性,用Spring進行Web開發會在某些方面擁有比Java更好的開發體驗。

(3)前端開發

Kotlin還有兩個強大的特性:dynamic類型及類型安全的建構器。前者實作其與JavaScript互通,後者可以幫助開發者建構可靠的HTML頁面。你可以嘗試使用Kotlin來建構UI。

(4)原生環境開發

因為Kotlin Native這個項目,Kotlin終于告别了Java,離開了JVM,直接編譯成機器碼供系統環境運作。雖然Kotlin Native尚處于早期階段,但後續的發展非常值得期待。如果你家裡有一個樹莓派,不妨可以用它來試一試。

如你所見,Kotlin還是一門非常開放、具有強大生态的程式設計語言。如果說與Java相容能讓它運作在所有支援Java的地方,那麼它的革命創新使得它超越了Java,進入了更加廣闊的世界。

1.4 本章小結

本書中每章都會有個小結,但第1章比較特别,我們打算用一個比喻來結尾。這個生動形象的說法來自于Lutz Hühnken的部落格,他把Java、Scala、Kotlin比作滑雪運動中的不同種類。

如果說JVM平台是一個滑雪世界,那麼最早的Java語言就是大家熟知的滑雪方式—雙腳各踏一個滑雪闆來進行滑雪。Scala則更像将兩隻腳都站在一塊闆上來滑行的滑雪方式。那些用滑雪單闆的高水準運動員非常令人羨慕,因為他們可以用更優雅的姿勢獲得更快的速度,而且最重要的是他們可以做“深粉雪”滑行,這也就是所謂的函數式程式設計。

然而,對于用雙闆滑雪的運動員而言,嘗試用單闆來滑雪,就像是學習一種新的運動,會經常摔跤。其實,大部分人還是更樂意用雙闆來進行滑雪。這時,刻滑闆出現了,使用它,運動員完全可以保留原有雙闆的滑雪習慣,但同時依舊可以做某個程度上的深粉雪滑行。你猜得沒錯,它就是Kotlin。

對于滑雪這項運動而言,别忘了,還有一個世界性的賽事—Android開發,它暫時并沒有對單闆開放,但對刻滑闆則已經敞開了懷抱。

是以,如果你想要尋找一種更好的Java語言的話,歡迎來到Kotlin的“滑雪”世界!

繼續閱讀