為什么我們建議嘗試一下新穎簡(jiǎn)潔的現(xiàn)代語(yǔ)言Kotlin
- 對(duì)Android的***支持為迅速發(fā)展的Kotlin語(yǔ)言提供了額外的推動(dòng)力,我們也正在密切關(guān)注Kotlin / Native(基于LLVM,可以將Kotlin代碼編譯為原生可執(zhí)行文件)的進(jìn)展。在使用Anko庫(kù)開(kāi)發(fā)Android應(yīng)用時(shí),我們已經(jīng)嘗到了空指針安全、數(shù)據(jù)類(lèi)和易于構(gòu)建DSL的甜頭。盡管初始編譯速度慢,且只有IntelliJ才提供***的IDE支持,但我們?nèi)匀唤ㄗh嘗試一下這種新穎簡(jiǎn)潔的現(xiàn)代語(yǔ)言。
由于最近在客戶(hù)項(xiàng)目上有機(jī)會(huì)使用了Kotlin這門(mén)今年大熱的語(yǔ)言,所以在好幾個(gè)不同的場(chǎng)合都被要求做一些Kotlin相關(guān)的分享,在這個(gè)過(guò)程中被問(wèn)到的最多的一個(gè)問(wèn)題便是——我們?yōu)槭裁匆獓L試Kotlin?
(圖片來(lái)自:http://suo.im/4hXHdp)
實(shí)際上客戶(hù)早在去年年初的時(shí)候便已經(jīng)完成了他們的后端技術(shù)選型,而Kotlin在那個(gè)時(shí)候便已經(jīng)成為了項(xiàng)目構(gòu)建后端微服務(wù)的主要語(yǔ)言。所以在這些分享中我并沒(méi)能給出一個(gè)很好的答案,而這個(gè)問(wèn)題本身也引起了我的思考。
首先我們看看Kotlin語(yǔ)言的特點(diǎn),官方羅列了4個(gè)顯著的特點(diǎn):
- 簡(jiǎn)潔 Consice
- 安全 Safe
- 友好的開(kāi)發(fā)工具 Tool-friendly
- 和Java的互操作性 Interoperable
簡(jiǎn)潔 Concise
Kotlin的簡(jiǎn)潔體現(xiàn)在很多方面,對(duì)于Java程序員來(lái)說(shuō),最直接的體現(xiàn)便是在Kotlin語(yǔ)法中直接省略了分號(hào),并且在構(gòu)造一個(gè)類(lèi)的實(shí)例時(shí)省略了new關(guān)鍵字,下面便是一段標(biāo)準(zhǔn)的Kotlin代碼:
- fun sayHi(name: String): String {
- val sb = StringBuilder(str = "Hi ")
- sb.append(name)
- return sb.toString()
- }
讓我們?cè)倏匆粋€(gè)Kotlin官網(wǎng)的示例代碼,來(lái)體會(huì)一下Kotlin的簡(jiǎn)潔:
- data class Customer(val name: String, val email: String, val company: String)
簡(jiǎn)單的一行代碼便實(shí)現(xiàn)了一個(gè)包含了constructor以及默認(rèn)getters, toString, equals, hashCode和copy實(shí)現(xiàn)的Pojo,而同樣的java實(shí)現(xiàn)需要大概50多行代碼, 即便是在Lombok的幫助下仍然需要十幾行代碼。
Kotlin還在Java集合類(lèi)的基礎(chǔ)上進(jìn)行了封裝,并提供了非常豐富的集合操作。同時(shí)結(jié)合非常簡(jiǎn)潔的Lambda表達(dá)式,使得調(diào)用更加精簡(jiǎn)。
- val numbers = 1..10
- val doubles = numbers.map {it * 2}
- val sumOfSquares = doubles.fold(0) {x,y -> x+y}
除了這些,Kotlin還提供了很多類(lèi)似字符串模板、標(biāo)準(zhǔn)函數(shù)庫(kù)、運(yùn)算符重載的特性,這些特性使得代碼可以非常簡(jiǎn)潔易讀,極大提升了開(kāi)發(fā)者的體驗(yàn)。
從實(shí)際項(xiàng)目來(lái)看,Kotlin的簡(jiǎn)潔在代碼量上表現(xiàn)的非常明顯,一個(gè)提供了24個(gè)API的Spring Boot微服務(wù),通過(guò)Kotlin編寫(xiě)的代碼量在8000行左右(含測(cè)試代碼)。同樣規(guī)模的微服務(wù)用Java編寫(xiě)的情況下代碼量將遠(yuǎn)大于這個(gè)數(shù)字。
安全 Safe
許多編程語(yǔ)言(包括 Java)中最常見(jiàn)的陷阱之一是訪問(wèn)空的指針,導(dǎo)致空指針異常。Kotlin的安全性主要體現(xiàn)在它對(duì)Null-Safety的支持上。能夠使代碼在編譯期間就察覺(jué)到可能的NullPointerException,讓Java developer能夠輕松擺脫NullPointerException。
- var output: String
- output = null // Compilation error
- val name: String? = null // Nullable type
- println(name.length()) // Compilation error
同時(shí)Kotlin還提供了一些自動(dòng)轉(zhuǎn)型及類(lèi)型推斷的特性,在提供安全檢查的同時(shí)也帶來(lái)了便捷。
下面也是一個(gè)來(lái)自官網(wǎng)的樣例,Kotlin在類(lèi)型檢查得到true后,自動(dòng)完成了Any到Invoice類(lèi)型的轉(zhuǎn)換:
- fun calculateTotal(obj: Any) {
- if (obj is Invoice)
- obj.calculateTotal()
- }
友好的開(kāi)發(fā)工具 Tool-friendly
這個(gè)特點(diǎn)就不用多說(shuō)了,引用官網(wǎng)那句傲嬌的原話(huà)就是 “It’s what we do best!”
和Java的互操作性 Interoperable
簡(jiǎn)單來(lái)說(shuō)這個(gè)特性就是Kotlin和Java是可以相互調(diào)用的。
這意味著我們可以利用任何已有的Java libraries來(lái)構(gòu)建我們的應(yīng)用,讓我們無(wú)需放棄我們所熟悉的一切便可以享受Kotlin給我們帶來(lái)的愉快的編程體驗(yàn)。
- ...
- import org.springframework.data.jpa.repository.JpaRepository
- import org.springframework.data.jpa.repository.JpaSpecificationExecutor
- ...
- interface AreaRepository : JpaRepository<AreaEntity, Long>, JpaSpecificationExecutor<AreaEntity> {
- fun existsByAreaId(id: UUID): Boolean
- fun findOneByAreaId(areaId: UUID): AreaEntity?
- }
例子中是項(xiàng)目上一個(gè)用Kotlin編寫(xiě)的基于Spring JPA的Repository,可以看到得益于Interoperable的特性,在嘗試使用Kotlin時(shí)我們可以依賴(lài)的是一個(gè)完整的Java生態(tài)圈。我們依然可以使用我們所熟悉的框架、構(gòu)建工具、開(kāi)發(fā)工具和測(cè)試工具。
如何開(kāi)始?
看了這么吸引人的語(yǔ)言特性,或許你已經(jīng)忍不住想要嘗試Kotlin了。但是實(shí)際情況可能是項(xiàng)目已經(jīng)開(kāi)始了一段時(shí)間,我們已經(jīng)用Java為項(xiàng)目構(gòu)建了很多功能。這個(gè)時(shí)候引入一個(gè)新的語(yǔ)言可能會(huì)給項(xiàng)目帶來(lái)一定的風(fēng)險(xiǎn)。那么我們可以如何開(kāi)始呢?
使用Kotlin編寫(xiě)單元測(cè)試
如果你比較保守,那么你可以開(kāi)始嘗試在項(xiàng)目中僅通過(guò)Kotlin來(lái)編寫(xiě)單元測(cè)試,同樣得益于Interoperable這個(gè)特性,我們可以輕松的使用Kotlin來(lái)為Java類(lèi)編寫(xiě)單元測(cè)試。這樣你可以不用擔(dān)心嘗試Kotlin為你的業(yè)務(wù)代碼帶來(lái)風(fēng)險(xiǎn),同時(shí)也可以在編寫(xiě)單元測(cè)試的過(guò)程中嘗試Kotlin語(yǔ)言的各種特性。
使用Kotlin來(lái)擴(kuò)展
你還可以使用Kotlin來(lái)豐富項(xiàng)目中所用到的Library,使用Kotlin Extensions來(lái)在不需要繼承的情況下完成對(duì)原有類(lèi)型的擴(kuò)展?;蛘咧苯油ㄟ^(guò)Kotlin來(lái)編寫(xiě)工具類(lèi)為項(xiàng)目服務(wù)。
- //Extensions.kt
- fun String.lastChar() = this.get(this.length - 1)
- fun KPerson.fullName() = "${this.firstName} ${this.lastName}" //String template
- //Java JUnit test
- Test
- public void lastChar() throws Exception {
- assertEquals('n', Extensions.lastChar("Kotlin"));
- }
- Test
- public void fullName() throws Exception {
- KPerson k = new KPerson("Foo", "Bar", Gender.MALE, 18);
- assertEquals("Foo Bar", Extensions.fullName(k));
- }
使用Kotlin來(lái)重寫(xiě)微服務(wù)
如果你在使用基于Spring Boot的微服務(wù),那么完全可以挑選一個(gè)優(yōu)先級(jí)較低的服務(wù)逐步通過(guò)Kotlin進(jìn)行改寫(xiě)。你會(huì)發(fā)現(xiàn)這個(gè)轉(zhuǎn)變會(huì)發(fā)生的無(wú)比順滑。因?yàn)镵otlin不會(huì)改變你之前通過(guò)Spring Boot構(gòu)建微服務(wù)的方式。
這三個(gè)方法都可以讓你在風(fēng)險(xiǎn)可控的情況下嘗試Kotlin。讓你在感受Kotlin語(yǔ)言帶來(lái)的美好編程體驗(yàn)的同時(shí),使整個(gè)團(tuán)隊(duì)逐漸熟悉Kotlin語(yǔ)言。你將會(huì)發(fā)現(xiàn)對(duì)于一個(gè)Java程序員來(lái)說(shuō),學(xué)習(xí)Kotlin真的是一件非常容易的事情,可以說(shuō)一旦開(kāi)始你就再也回不去了。
技術(shù)雷達(dá)
正在我們還在猶豫是否要嘗試Kotlin的時(shí)候,***一期技術(shù)雷達(dá)上Kotlin的表現(xiàn)又給了我們一個(gè)難以抗拒Kotlin的理由。雖然在雷達(dá)的描述中,我們更關(guān)注的是Kotlin在Android Native領(lǐng)域的影響力,但是隨著Spring社區(qū)對(duì)Kotlin的支持和更過(guò)成功項(xiàng)目的出現(xiàn),相信Kotlin會(huì)繼續(xù)向雷達(dá)的圓心邁進(jìn)。