自從Oracle收購Sun以後,對Java收費或增強控制的嘗試從未間斷,谷歌與Oracle圍繞Java API的官司也跌宕起伏。雖然Oracle只是針對Oracle JDK8的升級收費,並釋放了OpenJDK一直開源這份善意,可是若是沒有各個大非Oracle的JVM、JDK和衆多其它基於JVM的語言,Oracle這份善意能維持到何時可很差說。html
大廠要從JVM和JDK的層面早作打算,而廣大中小企業,就只能先從Java語言的層面,先找到Oracle之外的備胎。自從被谷歌欽定爲Android開發首選語言以後,採用Apache2.0 License的Kotlin逐漸進入大衆的視野。從領域語言到通用語言,基於JVM的語言選擇衆多,Kotlin能脫穎而出被谷歌相中,除了License的友好外,天然有其獨到之處(我的以爲基於Python語法的Jython在當時也算是一個強強聯合的選擇,固然如今來看Kotlin的優點明顯)。咱們先從摘自網上的一個段子來感覺下Kotlin的特色:java
固然,團隊開發比我的開發要考慮的問題更多,本文從研發團隊的視角,來審視在服務端開發項目中是否應該使用Kotlin。而關於Kotlin語言細節,詳情請你們參移動Kotlin官方文檔或搜索引擎去了解更多,本文就不詳細展開。git
做爲團隊技術預研,我已小試牛刀使用Kotlin作了一小一中真實上線項目,包括CI\CD、Spring全家桶、MyBatis、RDMS、NoSQL、消息隊列、微服務、RESTful接口、鑑權、計費等全面實踐,除項目代碼以外的也用Kotlin實現了爬蟲、運維、測試工具等。這其中除了BenchMark性能測試因OpenJDK:jmh直接操做字節碼而須要編譯比java略複雜外,全部事件都能作到人(Java)無我(Kotlin)有,人(Java)有我(Kotlin)強,隻身十天左右就能高質量從零完成一套AI SaaS服務的開發、測試。github
我自身的實踐能夠說明,Kotlin使用Java的開源組件、類庫、工具棧上與Java代碼自己幾乎(僅發現jmh有些許差異外)沒有差異,這是其它基於JVM的語言沒法比擬有優點。web
2.1 強制非空校驗shell
// 全部變量默認不能爲空 var a: String = "abc" a = null //編譯錯誤 // 若是想要容許變量爲空,變量聲明中的類型以"?"結尾 var b: String? = null // 非空類型的變量,能夠直接調用對象方法 println(a.length) // 可空類型的變量,能夠用"?."替換"."來進行徹底調用 println(b?.length) //若是b爲null,則b?.length返回null,而不會拋出NPE // "?."鏈式調用更顯安全調用的威力 bob?.department?.head?.name //只要有一環爲null,則整個表達式返回null // 空類型不能直接賦值給非空類型 a = b //編譯錯誤 // 可使用非空斷言"!!"來強制將b轉換爲其對應的非空類型 a = b!! //若是b爲null,則拋出NPE,不然賦值成功 // 更安全的作法是使用"?:"賦值 a = b?:"Default" // "?:"還能夠接」throw「、"return"、"break"語句來提早結束函數或語句塊 a = b?: throw MyException("自定義異常")
能夠看到,Kotlin經過強制非空校驗機制,規避了Java最易犯的NPE問題,而且在不額外增長判空代碼的狀況下,很容易寫出空安全的代碼,固然也經過非空斷言保留了拋出NPE的途徑,具體請參考Kotlin官方文檔-空安全編程
2.2 只讀變量安全
// 經過val能夠方便聲明只讀變量,防止變量的誤修改,相似於java的final val a = "Hello" //... a = "world" //編譯錯誤 // var用於聲明可讀寫變量 var b = 1 //若是下方沒有代碼對b進行修改,則編譯告警
聲明只讀變量的語法更簡潔,配合var未修改編譯告警,強制開發人員明白無誤地聲明變量服務器
3.1 默認參數與數據類session
// 默認參數,大多數狀況能夠代替函數重載 fun a(name: String, age: Int = 0) { //... } // data關鍵字會自動爲類型增長hashCode(),equals(),copy(),toString()方法 // val關鍵字會自動生成只讀成員變量及get方法 // var關鍵字會自動生成成員變量及get和set方法 data class Person(val id: Int, var name: String, var age: Int = 0) //以上就是Person實體的完整聲明,它等價於十行以上的java代碼
默認參數、數據類、主構造函數的組合使用,讓咱們節省了90%以上的實體聲明代碼,且表達能力更清晰,可維護性更強
3.2 類型推斷
when(val u = request.session.getAttribute("user")){ is String -> println(u.toUpperCase()) is Map<*, *> -> println(u["name"]) !is List<*> -> println(u) }
在類型判斷代碼以後,變量會自動轉換爲須要的類型,省去變量聲明和類型轉換代碼。
除此以外Kotlin擁有着豐富的集合操做,以及類擴展、更簡潔的lambda、字符串模板、操做符重載、解構等等幾乎包含了如今語言的全部優良特徵,讓業務代碼節省50%以上,且表義能力更強。
Spring-Boot已經將kotlin提高爲僅次於Java的推薦語言,足以見得Spring對Kotlin重視
4.1 構造函數注入
Spring構造函數注入配置kotlin的主構造函數語法,Spring+Kotlin天生就很搭
@Service class SMSService( @Value("\${sms.appId}") private val appId: String, @Value("\${sms.appSecret}") private val appSecurity: String, private val webClient: WebClient ) { //... }
4.2 針對Kotlin的擴展
Spring中還有部分專門針對Kotlin的擴展如: SpringApplicationExtension:
@SpringBootApplication class SpringBootApplicationStarter fun main(args: Array<String>) { //拉起Spring-Boot應用 runApplication<SpringBootApplicationStarter>(*args) }
4.3 針對Kotlin的示例代碼
Spring文檔專門爲Kotlin編寫了示例代碼,這但是Spring支持的老牌語言Groovy多年都沒享受到的待遇:
Kotlin天生對Spring的友好,以及Spring對Kotlin的重視和加成,能夠預見Kotlin將來在服務器開發領域的地位會愈來愈高。
Kotlin首選開發工具非同屬jetbrain公司的IDEA莫屬
Eclipse+Kotlin Plugin也是不錯的選擇
兩者Kotlin的開發體驗都不輸於Java的開發體驗
不過Eclipse的Kotlin插件存在兩個問題:
1) Debug不能自動識別Kotlin的main方法,須要手工填入Class名;
2) Debug不支持Kotlin編譯的allopen選項,全部Bean和Configuration類型須顯示聲明爲open
@SpringBootApplication open class SpringBootApplicationStarter @Configuration open class BeanConfig @Service open class TestService @RestController open class TestController
在IDE以外,Kotlin能完美地運行於Maven和Gradle之上,CI/CD工具Jenkins天然不在話下,JUnit、Swagger等Java原有工具鏈運行起來都沒有差異,在字節碼和jar包以外的各類工具可否運行,理論上並不取決於項目代碼是Kotlin仍是Java;可能最大的問題在於,原有的代碼檢查工具不能再繼承使用。
Kotlin放開了不少限制如:
這帶來了諸多便利,如同一領域的實體能夠聲明在一個文件中:
//WebResponses.kt open class WebResponse(var errorCode: Int = 0, var errorMsg: String? = null) open class DataResponse<T>(var data: T?) : WebResponse() open class MapResponse<K, V>(map: Map<K, V>) : DataResponse<Map<K, V>>(map) { constructor(vararg pairs: Pair<K, V>) : this(mutableMapOf(*pairs)) }
能夠很方便地擴展已有類庫
// StringExtensions.kt val REGEX_Digits = Regex("\\\d+") fun String.isDigits(): Boolean { return this.matches(REGEX_Digits) } // ACLInterceptor val appId = request.getParameter("appId") if (!appId.isNullOrBlank() && appId.isDigits()) { //... }
可是若是不加限制,很難保證開發人員不爲所欲爲。因此應該針對Kotlin項目制定一些編碼規範(能夠與Android項目共用),如:
對Java開發人員來講,學習Kotlin並非什麼困難的事情,以我我的的經驗,直接以一個小項目開始的狀況下,一週以內編碼效率就會明顯超過Java。
固然,語言工具不是項目成敗的決定性因素,使用工具的人才是,不妨先讓項目組中的核心成員去了解下Kotlin,再作決定。
快速上手建議從Koans開始,想要更深刻地掌握,仍是要閱讀Kotlin官方文檔
在Spring項目中使用Kotlin會使依賴增長4.18MB左右
這在Spring-Boot興起以前,對我來講確實是個問題,6年前一個war包也就3~5MB大小,還要爲Tomcat能部署多個服務而不會代碼空間溢出,把war包進一步瘦身——把公共jar包都放入Tomcat/lib之下。
而如今Spring-Boot項目動則30MB起步的大小,讓我已經再也不考慮服務器資源的問題,而更享受各類組件和工具帶來的開發效率提高。
固然這個問題,因項目實際狀況而異,須要交給做爲架構師的你本身去決策。
具體細節本不是此文的討論目標,且對Kotlin作BenchMark性能測試不是那麼困難,可是Kotlin的BenchMark資料也很少,這裏我附送一個簡明教程:
mvn archetype:generate \ -DinteractiveMode=false \ -DarchetypeGroupId=org.openjdk.jmh \ -DarchetypeArtifactId=jmh-kotlin-benchmark-archetype \ -DgroupId=org.sample \ -DartifactId=test \ -Dversion=1.0
@BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.MILLISECONDS) open class MyBenchmark { @Benchmark fun testMethod1() { //... } @Benchmark fun testMethod2() { //... } }
mvn clean package java -jar target/benchmarks.jar
更多性能測試詳情,可參考
無論怎麼說,語言工具不是項目成敗的決定性因素,使用工具的人才是,不妨先讓項目組中的核心成員去了解下Kotlin,再作決定。