這是團隊內部分享的Kotlin的知識點,還在不斷完善的階段。團隊用Kotlin作為後端開發語言已經一年多,知識點還在不斷的挖掘規範中。期待和更多的喜歡Kotlin的同學們一起討論。
val:只讀變量,可以之後初始化,不過如果未初始化之前該變量無法使用,編譯器會報錯,編譯成字節碼的時候編譯器應該會做優化,不建議之後初始化,什麼時候用到什麼時候定義。
Var:可變(略)
2:類型推導
kotlin雖然是一種強類型的jvm語言,一定程度上保證了類型安全,但是基於好的編碼習慣,除非特別明顯類似於val a = Example()這種,其他儘量不要省略類型,尤其一些函數,省略返回類型有時候可能會出現問題。
3:Array
case 1: val a:Array
case 2:val b:Array
4:import renaming
import renaming可以使用,注意到是,如果重命名後,只能使用重命名之後的聲明,和正常的import一樣。
另外,有意思的是你可以重定義和重命名相同的名字,不過該文件內會優先選擇import的聲明。
5:range
a:閉區間(..)for:val range:IntRange= 1 .. 5 包括1和5
b:半開半閉區間(until)for:val range : IntRange = 1 until 5 包括1不包括5
6:異常
不同於Java,kotlin中所有的異常都是unchecked異常。
7:引用相等和結構相等
結構相等(==):默認會調用equal方法(如果不重寫equal方法,Any默認的equal方法好像是判斷引用是否相等)
引用相等(===):判斷飲用指向的是否是同一實例
注意:結構相等對於null也是安全的,編譯器會作null檢查,如果都是null則返回true。
8:訪問修飾符(默認public)
- public:默認修飾符,被其修飾的在任何位置都能訪問
- private:只能在當前源文件內使用
- internal:在同一模塊內使用
- protected:無效修飾符,只用於類和接口內
9:控制流作表達式
不同於Java,if .. else /try.. catch在kotlin中都是表達式,表達式意味著控制流可以直接作為右值。
10:自動類型轉換
11:顯示類型轉換(as)
as 轉換失敗會跑異常,所以使用as的時候要注意,這裡可能會拋異常,如果不想拋異常,可以使用is,另外,as轉換後可能會返回null,賦值編譯器並不會幫你做檢查,所以coding過程中要注意。Case如下:
12:when
when(arg):有點類似於窮舉,判斷當前arg處於哪個分支,在這裡不要想著做所謂的bool判斷,不支持,可以針對arg做bool判斷,比如用in。
When:分支全是bool判斷。
13:類型結構
Any:類似於Java的Objevt
Unit:不同於void,Unit也是一個實實在在的類型,只不過是singleton instane。
Nothing:所有類的子類。
14:構造函數
主構造函數:val/var可要可不要,如果不要則默認沒有getter/setter方法,這塊我覺得如果沒有val/var其實就是傳了個參數過去,class中並沒有這個字段。
非主構造函數:val/var必須不要,一定要調用主構造函數。
15:初始化順序(這裡不考慮實力化過程中內存分配時的初始化,只是從kotlin語法上考究)
- 字段初始化賦初值
- init
- 構造函數
與Java構造代碼塊不同的是,init有點類似於pre constructor,不比在乎字段是在init之前或者之後。
16:嵌套類
inner class:和外部類有關聯,需要依賴於一個外部類實力,外部類一切對其可見。
static class:和外部類沒什麼關聯,只是定義在外部類內部。
17:object /function/companion
其本質都是生成一個final類,其方法都被標註為static。
備註:這塊沒怎麼研究,有時間可以看看字節碼。
18:代理(by)
19:密閉類(可以理解成是類型的枚舉,使用時需要該類型的實例)
20:local functions(外部不可訪問,作用域內變量對其都可見)
21:函數默認參數
重寫的時候必須完整的函數簽名,且重寫函數不允許再次指定參數默認值
22:擴展函數(成員擴展函數可以被重寫,沒什麼需要特別注意的地方)
23:函數字面量(值得注意的是如果參數可以推導出來可以省略)
24:尾遞歸
如果函數定義中用到了遞歸,且返回值就是其遞歸調用,則可以採用尾遞歸,編譯器會自動優化調用過程,採用迭代方式執行該調用,不至於產生那麼多遞歸棧。
25:varargs
如果該關鍵字標識的參數不是最後一個,則之後的參數要採用命名參數傳遞實參。
26:Spread operator
27:Apply
28:Let
29:Run
30:Lazy
31:Use
32:Repeat(從0開始)
33:require/assert/check
項目中這幾個用的很少,一般都定義自己的require/assert/check進行相應的拋異常和處理操作。
34 : SAM( TODO )
35 : top-level functions
編譯器根據包名生成和包名同名的 class ,所有的函數都以 static 形式成為該 class 的成員函數。
36 :匿名函數
37 :函數引用
38 : typealias
39 : 屬性
同 Java 初始化構造快, kotlin init 用到的屬性必須要先定義,否則無法在 init 塊中使用。
40 :延遲初始化
- 不能是基本類型
- 不能自定義 getter/setter
- 如果未賦值使用的話會抱異常
41 :代理屬性( TODO )
42 : lazy initialization
用法有三種,詳情都在上面,細節可以參考詳細介紹,有時間可以仔細鑽研一下。
43:lazy versuslateinit
- lazy只能用於val變量,lateinit只能用於var變量
- lateinit不能用於null
44:Observables
用來監控屬性變化和對屬性進行約束
45:not-nullproperty delegate
感覺功能有點類似於lateinit
46:as[?]
不安全,轉換不成功會拋異常,可以用as?,安全轉換,如果轉換不成功會返回null
47:Optional
不用多說
48:Upper Bounds
class UpperBoundsTest< T , V , X > where T :Comparable< X > , T :Serializable , V :Serializable , V :Comparable< X >
49:out/in
in用法省略,和out相同,繼承語義和out正好相反。
50:未完待續
編碼規約建議
- kotlin非空斷言(!!)儘量不要使用。
- 最好不要出現warning,如果有最好處理掉。
- 能用枚舉的話最好用枚舉,不要習慣使用字面量。
- 能用全局變量就用全局變量,最好不要全都用字面量。比如如果頻繁的出現1000、10000可以用全局變量千/萬來替代,可讀性會更好。
- 建議使用統一的命名規範,比如grpc的實現採用統一的命名規則,模型層採用和數據表同名的方式,以便迅速定位哪個類屬於數據表的模型實現,其他的業務也如此,便於查找相關聯的業務。
原文鏈接:https://mp.weixin.qq.com/s/vvJZq6ZS4-10CQchyLD-dg 如有侵權請聯繫刪除
閱讀更多 全棧取經之路 的文章