kotlin簡介
Kotlin是由JetBrains公司(IDEA開發(fā)者)所開發(fā)的編程語言搅窿,其名稱來自于開發(fā)團(tuán)隊(duì)附近的科特林島萍歉。
多平臺開發(fā)
JVM :Android; Server-Side
Javascript:前端
Native(beta) :開發(fā)原生應(yīng)用 windows、macos、linux
Swift與Kotlin非常像
http://nilhcem.com/swift-is-like-kotlin/
kotlin發(fā)展歷程
java發(fā)展歷程
JVM語言的原理
JVM規(guī)范與java規(guī)范是相互獨(dú)立的
只要生成的編譯文件匹配JVM字節(jié)碼規(guī)范,任何語言都可以由JVM編譯運(yùn)行.
Kotlin也是一種JVM語言,完全兼容java暇仲,可以與java相互調(diào)用;Kotlin語言的設(shè)計(jì)受到Java副渴、C#奈附、JavaScript、Scala煮剧、Groovy等語言的啟發(fā)
kotlin的特性
下面不會去列舉語法斥滤,而是主要介紹kotlin中我認(rèn)為比較重要的特性和背后的東西将鸵。
類型推斷
空類型設(shè)計(jì)
函數(shù)式編程
類型推斷
類型推斷是指編程語言中在編譯期自動推導(dǎo)出值的數(shù)據(jù)類型。推斷類型的能力讓很多編程任務(wù)變得容易佑颇,讓程序員可以忽略類型標(biāo)注的同時仍然允許類型檢查顶掉。
在開發(fā)環(huán)境中,我們往往寫出表達(dá)式挑胸,然后可以用快捷鍵來生成變量聲明痒筒,往往都是很準(zhǔn)的,這說明了編譯器其實(shí)是可以很準(zhǔn)確的推斷出來類型的茬贵。編程語言所具備的類型推斷能力可以把類型聲明的任務(wù)由開發(fā)者轉(zhuǎn)到了編譯器.
java中聲明變量的方式是類型寫在最前面簿透,后面跟著變量名,這就迫使開發(fā)者在聲明變量時就要先思考變量的類型要定義成什么闷沥,而在一些情況下比如使用集合萎战、泛型類型的變量,定義類型就會變得比較繁瑣。
Kotlin中聲明變量聘殖,類型可以省略慷嗜,或者放到變量名后面,這可以降低類型的權(quán)重莱衩,從必選變?yōu)榭蛇x,降低開發(fā)者思維負(fù)擔(dān)。java10中也引入了類型推斷奄妨。
Javascript中聲明變量也是用關(guān)鍵字var,但是還是有本質(zhì)區(qū)別的,Kotlin中的類型推斷并不是變成動態(tài)類型苹祟、弱類型砸抛,類型仍然是在編譯期就已經(jīng)決定了的,Kotlin仍然是靜態(tài)類型树枫、強(qiáng)類型的編程語言直焙。javascript由于是弱類型語言,同一個變量可以不經(jīng)過強(qiáng)制類型轉(zhuǎn)換就被賦不同數(shù)據(jù)類型的值砂轻,
編程語言的一個趨勢就是抽象程度越來越高奔誓,編譯器做更多的事情。
空類型設(shè)計(jì)
空類型的由來
托尼·霍爾(Tony Hoare)搔涝,圖靈獎得主
托尼·霍爾是ALGOL語言的設(shè)計(jì)者厨喂,該語言在編程語言發(fā)展歷史上非常重要,對其他編程語言產(chǎn)生重大影響,大多數(shù)近代編程語言(包括C語言)皆使用類似ALGOL的語法庄呈。他在一次大會上討論了null應(yīng)用的設(shè)計(jì):
“我把 null 引用稱為自己的十億美元錯誤蜕煌。它的發(fā)明是在1965 年,那時我用一個面向?qū)ο笳Z言( ALGOL W )設(shè)計(jì)了第一個全面的引用類型系統(tǒng)诬留。我加入了null引用設(shè)計(jì)斜纪,僅僅是因?yàn)閷?shí)現(xiàn)起來非常容易颁褂。它導(dǎo)致了數(shù)不清的錯誤、漏洞和系統(tǒng)崩潰傀广,可能在之后 40 年中造成了十億美元的損失颁独。”
null引用存在的問題
以java為例伪冰,看null引用的設(shè)計(jì)到底存在哪些問題
空指針問題NPE
編譯時不能對空指針做出檢查誓酒,運(yùn)行時訪問null對象就會出現(xiàn)錯誤,這個就是工程中常見的空指針異常贮聂。
null本身沒有語義靠柑,會存在歧義
值未被初始化
值不存在
也許表示一種狀態(tài)
邏輯上有漏洞
Java中,null可以賦值給任何引用吓懈,比如賦值給String類型變量歼冰,String a = null,但是null并不是String類型: a instanceof String 返回的是false耻警,這個其實(shí)是有些矛盾的隔嫡。所以當(dāng)持有一個String類型的變量,就存在兩種情況甘穿,null或者真正的String.
解決NPE的方式:
防御式代碼
在訪問對象前判空腮恩,但會有冗余代碼;會規(guī)避問題温兼,而隱藏真正的問題
拋出異常給調(diào)用方處理
方法中傳參傳入的空值秸滴、無效值,拋出受檢查異常給上層調(diào)用方
增加注解
Android中可以增加@NonNull注解募判,編譯時做額外檢查
空狀態(tài)對象設(shè)計(jì)模式
空狀態(tài)對象是一個實(shí)現(xiàn)接口但是不做任何業(yè)務(wù)邏輯的對象荡含,可以取代判空檢查;這樣的空狀態(tài)對象也可以在數(shù)據(jù)不可用的時候提供默認(rèn)的行為
java8 Optional類
java8中引入了Optional類届垫,來解決廣泛存在的null引用問題.官方j(luò)avadoc文檔介紹
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
Additional methods that depend on the presence or absence of a contained value are provided, such as orElse() (return a default value if value not present) and ifPresent() (execute a block of code if the value is present).
來看一下是如何實(shí)現(xiàn)的释液。
舉一個訪問對象讀取熟悉的例子
java 8 之前 :
java 8:
總結(jié):
1.用Optional還是會比較繁瑣,這個也說明了設(shè)計(jì)一個替代null的方案還是比較難的敦腔。
2. optional的耗時大約是普通判空的數(shù)十倍均澳,主要是涉及泛型、使用時多創(chuàng)鍵了一個對象的創(chuàng)建符衔;數(shù)據(jù)比較大時找前,會造成性能損失。
3. java8 引入Optional的意義在于提示調(diào)用者判族,用特殊類型包裝的變量可能為空躺盛,在使用取出時需要判斷
Kotlin的空類型設(shè)計(jì)
Kotlin中引入了可空類型和不可空類型的區(qū)分,可以區(qū)分一個引用可以容納null,還是不能容納null形帮。
String vs String?
String 類型表示變量不能為空槽惫,String?則表示變量可以為空 String?含義是String or null.這兩種是不同的類型.
比如:
var a:String = “abc” //ok
var a:String = null //不允許
var b :String? = null //ok
a=b // 不允許
String?類型的值不能給String類型的值賦值
這樣就將類型分成了可空類型和不可能類型,每一個類型都有這樣的處理;Kotlin中訪問非空類型變量永遠(yuǎn)不會出現(xiàn)空指針異常周叮。
同樣上面的例子,采用Kotlin去寫界斜,就會簡潔很多
編程范式-函數(shù)式編程
編程范式是什么仿耽?
編程范式是程序員看待程序和寫程序的觀點(diǎn)
主要的類型:
非結(jié)構(gòu)化編程、結(jié)構(gòu)化編程各薇、面向?qū)ο缶幊滔詈亍⒚钍骄幊獭⒑瘮?shù)式編程
這些類型并不是彼此互斥的峭判,而是按照不同的維度做的劃分开缎,一種編程語言可能都支持多個編程范式
非結(jié)構(gòu)化編程
第一代的高級語言往往是非結(jié)構(gòu)化編程 比如 BASIC語言
每一行的代碼前面都有一個數(shù)字作為行號,通常使用GOTO的跳躍指令來實(shí)現(xiàn)判斷和循環(huán).
看一下下面這段代碼是做什么的:
實(shí)際上做的是:程序在屏幕上顯示數(shù)字 1 到 10 及其對應(yīng)的平方?
采用這種方式寫程序,大量的使用goto實(shí)現(xiàn)邏輯的跳轉(zhuǎn)林螃,代碼一長奕删,可讀性和維護(hù)性就比較差了,形成“面條式代碼”
結(jié)構(gòu)化編程
采用順序疗认、分支完残、循環(huán)結(jié)構(gòu)來表達(dá),禁用或者少用GOTO;
并用子程序來組織代碼侮邀,采用自頂向下的方式來寫程序
代表語言是C語言
實(shí)現(xiàn)同樣的邏輯:
可見采用結(jié)構(gòu)化編程坏怪,代碼的邏輯會更清晰贝润。
面向?qū)ο缶幊?/h2>
思想:
將計(jì)算機(jī)程序視為一組對象的集合绊茧,而每個對象都可以接收其他對象發(fā)過來的消息,并處理這些消息打掘,計(jì)算機(jī)程序的執(zhí)行就是一系列消息在各個對象之間傳遞华畏。
特性: 封裝性、繼承性尊蚁、多態(tài)性亡笑。
命令式編程
把計(jì)算機(jī)程序視為一系列的命令集合
主要思想是關(guān)注計(jì)算機(jī)執(zhí)行的步驟,即一步一步告訴計(jì)算機(jī)先做什么再做什么横朋。 “先做這仑乌,再做那”,強(qiáng)調(diào)“怎么做”
實(shí)現(xiàn):
用變量來儲存數(shù)據(jù)琴锭,用語句來執(zhí)行指令晰甚,改變變量狀態(tài)。
基本所有的常見的編程語言都具有此范式
函數(shù)式編程
聲明式語法决帖,描述要什么厕九,而不是怎么做
類似于SQL語句
語言: kotlin swift python javascript scala
特點(diǎn):
1. 函數(shù)是第一等公民
可以賦值給變量,可作為參數(shù)傳入另一個函數(shù)地回,也可作為函數(shù)的返回值
2. 純函數(shù) y=f(x)
只要輸入相同扁远,返回值不變
沒有副作用:不修改函數(shù)的外部狀態(tài)
舉個栗子
公司部門要進(jìn)行outing俊鱼,去哪里是個問題,要考慮多個因素畅买,比如花費(fèi)并闲、距離、天數(shù)等等谷羞,有多個備選地點(diǎn)進(jìn)行選擇焙蚓。
定義一個數(shù)據(jù)類:
要進(jìn)行篩選了,分別用sql,kotlin,java來實(shí)現(xiàn)
找出花費(fèi)低于2000元的outing地點(diǎn)信息
SQL
Kotlin
java 7
可見kotin的寫法還是比較接近于sql的思想的洒宝,聲明式的寫法购公,而不管具體如何實(shí)現(xiàn);其中的:place->place.money<2000 就是函數(shù)雁歌,可以作為參數(shù)傳遞給fliter這個高階函數(shù)宏浩;而且這個函數(shù)沒有副作用,不改變外部狀態(tài)靠瞎。
再來一個復(fù)雜一點(diǎn)的:
找出花費(fèi)低于5000元比庄,時間不多于4天,按照距離排序的outing地點(diǎn)名稱
SQL
Kotlin:
java 7
由此可見用kotlin的函數(shù)式寫法乏盐,會更簡潔佳窑,邏輯也更清晰,這段代碼的目標(biāo)一目了然父能,這種清晰在于實(shí)現(xiàn)了業(yè)務(wù)邏輯與控制邏輯的分離神凑,業(yè)務(wù)邏輯就是由函數(shù)實(shí)現(xiàn)的,比如place->place.money<500,而控制邏輯是由filter,sorterBy等高階函數(shù)實(shí)現(xiàn)的何吝。
而java的傳統(tǒng)寫法是基于對數(shù)據(jù)的操作溉委,避免不了遍歷的操作,業(yè)務(wù)邏輯與控制邏輯交織在了一起爱榕,這段代碼的目的就不是那么容易清晰看到的了瓣喊。
總結(jié)
kotlin是實(shí)用的現(xiàn)代編程語言,吸收了眾多編程語言的優(yōu)點(diǎn)黔酥,支持類型推斷藻三、空類型安全、函數(shù)式編程跪者、DSL等特性棵帽,非常值得學(xué)習(xí)和使用。
建議參考:
《Kotlin核心編程》
《Kotlin實(shí)戰(zhàn)》