Kotlin也沒那麼難(一)
do not speak,show my code...
基本概念
函式
kotlin: fun functionName(parameter1: Int, parameter2: Int): Int { //該函式返回兩者最大值 return if (parameter1 > parameter2) parameter1 else parameter2 }
java: Integer functionName(Integer parameter1, Integer parameter2) { //該函式返回兩者最大值 return parameter1 > parameter2 ? parameter1 : parameter2; }
要點:
- kotlin中沒有基本資料型別(int,float等),都是以物件形式存在(Int,Float),kotlin也沒有陣列,以Array類存在
- kotlin以 fun 關鍵字開頭,而java以 返回型別 開頭,kotlin的 返回型別 以 :返回型別 的形式銜接在函式宣告括號後
- kotlin的所有變數宣告都是 變數名: 變數型別 ,java則是 變數型別 變數名
- kotlin也有三目運算子,不過寫法是 if (表示式) 表示式正確時的值 else 表示式錯誤時的值 ,java則是 表示式 ? 表示式正確時的值 : 表示式錯誤時的值
- kotlin語句末尾可以省略分號
表示式函式體
kotlin中if是表示式,而不是語句。語句是沒有自己的值,而表示式是有值的。表示式可以作為其他表示式的一部分也可以作為函式的返回值。在kotlin中除了迴圈(for、do、while)以外大多數控制結構都是表示式。
所以上面的函式就可以簡化成以下程式碼:
fun functionStruct(parameter1: Int, parameter2: Int) = if (parameter1 > parameter2) parameter1 else parameter2
細心的朋友可能發現了上面的函式沒有宣告返回型別,因為對於返回一個表示式的函式來說,編譯器會自動分析返回型別,術語叫 型別推導
變數
kotlin不會以變數型別開頭,因為有些的變數宣告的型別是可以省略的
var number0 = 100 val number1 = 100 val number2 : Int = 100 val number3 //編譯不通過 val number4 : Int //編譯不通過
var表示該變數是可變變數,可以重新賦值
val表示該變數是不可變變數,不可以重新賦值
字串模板 "...${變數}..."
eg: var age = "my age is ${number0}"
,這種情況下大括號可以省略
String age = "my age is " + number0;
eg: "...${list.get(0)}..."
這個時候大括號不能省
類和屬性
kotlin中預設public修飾符
kotlin定義一個類最簡單的方法就是class People(var name: String, val age: Int)
以上程式碼定義了一個People類,該類有兩個屬性name和age
由於name被var修飾,所以kotlin會為name建立一個getter和一個setter方法
由於age被val修飾,所以kotlin會為name建立一個getter方法
使用起來很簡單
val my = People("name", 20) my.name = "new Name" println("my name is ${my.name} and my age is ${my.age}")
要點:
- kotlin建立物件是 Xxx() ,java是** new Xxx();**
- kotlin呼叫屬性的getter方法直接 xxx.property
- kotlin呼叫屬性的setter方法直接 xxx.property = value
注意:
如果寫成 class People(name: String, age: Int)
,即省略了var和val,則這兩個變數都只是建構函式用的臨時變數,也就是說kotlin不會再自動給People類建立name和age變數
自定義getter和setter方法
class People(var name: String, val age: Int) { var desc: String = "這是我的個人描述" get() { print("呼叫了getter方法") return "my name is $name and my age is $age" } set(value) { print("呼叫了setter方法") field = value } }
需要注意的是這裡有個 field 變數,這個變數術語叫做 幕後變數 ,這個後面我們會深入瞭解,這裡只需要知道把要更新的值賦予給該變數就OK啦
目錄和包
kotlin的包宣告形式和java一樣: package com.example.ice.kotlindemo
,不過有意思的是kotlin不強制包宣告和檔案路徑一致,也就是說該kotlindemo.kt檔案不必強制放在com/example/ice/目錄下。
kotlin檔案可以同時宣告多個類,甚至還可以宣告函式和變數!java中只能在類中宣告函式,並且一個java檔案只能有一個 public class 的而且該class類名還必須和檔名一致
列舉和When
enum
enum class Color { BLUE, RED, GREEN }
kotlin中enum是 軟關鍵字 ,只有出現在class面前才有特殊意義,其他情況你甚至可以當一個變數使用 val enum: Color = Color.BLUE
when
when有點類似java中的switch,但是when是表示式
kotlin: fun testWhen(enum: Color) = when (enum) { Color.BLUE -> "blue" Color.RED -> "red" Color.GREEN -> "green" else -> "default" }
java: public String testWhen(Color color) { String returnValue; switch (color) { case RED: returnValue = "red"; break; case BLUE: returnValue = "blue"; break; case GREEN: returnValue = "green"; break; default: returnValue = "default"; break; } return returnValue; }
要點:
- when不用java中的 break
- when用 -> 替代 java中的 case
- when用 else 替代java中的 default
- when是表示式不是語句塊
在when分支上合併多個選項
when (enum) { Color.BLUE, Color.RED -> "blue or red" Color.GREEN -> "green" else -> "default" }
when結構中可以使用任意物件
var people1: People = People("name1", 20) var people2: People = People("name2", 20) fun testWhen2(people: People) = when (people) { people1 -> "is people1" people2 -> { "is people2" } else -> "no match" }
要點:
- when表示式會把最後一行程式碼的結果當為返回值(見people2的情況,沒有寫return,但是會返回"is people2")
- when表示式某種情況下只有返回語句可以省略大括號(見people1的情況)
不帶引數的when
fun testWhen3() = when { 1 > 2 -> print("1 > 2") 2 > 1 -> print("2 > 1") else -> throw ArithmeticException("error") }
型別轉換
kotlin使用 is 代替java的 instanceof 進行型別判斷
kotlin使用 as 進行顯示轉換var num = 100 as Float
注意:as也可以用於匯入語句 import xxx.xxx.People as P
這樣P就代表了People
迴圈
kotlin的迴圈比較於java來說沒有很大的改變,但是多了一些關鍵字需要我們注意
var i = 0 for (i in 0..100) { //列印 01234..100 //for (i in 0 until 100) { //列印 01234..99 //for (i in 100 downTo 0 step 2) { //列印 1009896..0 print(i) }
in 常常用來迭代list或map
val list = listOf(1, 2, 3) for (i in list) { print(i) }
kotlin中使用 listOf 方法可以建立一個list
如果你想迭代list的同時獲取當前的index,可以使用如下寫法 for ((index, value) in list.withIndex()) { //(index,value)的寫法專業術語叫做解構宣告,後面我們會深入瞭解 print("index = $index and value = $value") }
in 也可以用來判斷物件是否在集合中
if (2 in list) { print("2 exist in list") }
!in 關鍵字
Emm,這個看前面一個 ! 就知道是和 in 相反的結果了
try catch finally
- kotlin沒有 throws 關鍵字(想起java被throws支配的恐懼了麼)
- try也是一個表示式
val myAge = try { 1 / 0 } catch (e: Exception) { print(e) } finally { 100 }
函式
集合建立
listOf(1, 2, 3) mutableListOf(1, 2, 3) setOf(1, 2, 3) mutableSetOf(1, 2, 3) mapOf(1 to "1", 2 to "2", 3 to "3") mutableMapOf(1 to "1", 2 to "2", 3 to "3")
有mutable字首的方法建立的集合,元素是可以增添、移除、修改的
預設引數
fun defaultParaFun(para1: Int = 0, para2: Int, para3: Int) = para1 + para2 + para3 defaultParaFun(para2 = 2, para3 = 4)
我們給引數para1設定了預設值0
在呼叫該函式的時候我們對傳入的值進行了顯示的宣告引數,比如2就是引數para2的值,3就是引數para3的值,此時函式返回值為5(0+2+3)
有意思的是如果我們給所有引數都加預設值:
fun defaultParaFun(para1: Int = 0, para2: Int = 1, para3: Int = 2) = para1 + para2 + para3 defaultParaFun() // 0+1+2 defaultParaFun(para3 = 5) // 0+1+5 defaultParaFun(para2 = 5) // 0+5+2 defaultParaFun(para1 = 5, para2 = 5) // 5+5+2
同時java是不支援預設引數的,所以我們可以給方法加上@JvmOverloads註解。這樣的話kotlin編譯器會將該方法生成一系列過載方法

result.png
由於我這個例子中 defaultParaFun 是直接寫在 KotlinDemo.kt 檔案中的(術語叫頂級函式),所以java呼叫要使用 KotlinDemoKt.defaultParaFun 形式,頂級函式是不是很像java中的靜態函式(kotlin是沒有static關鍵字的!)?
擴充套件函式
fun Int.add2(): Int { return this + 2 } print(0.add2())
要點:
- 我們定義了一個add2函式用於將一個 數+2 並返回
- add2函式面前使用 Int. 表示該函式是對Int類的擴充套件(就像是Int類本身的方法一樣)
- add2函式體內的this其實就是呼叫該方法的物件(本例中this就是0)
- this可以省略,就變成了
return +2
- java中呼叫就得寫成
KotlinDemoKt.add2(0)
其實就是被編譯成了靜態函式 - 如果Int類也有add2則優先呼叫Int類的add2函式,即成員方法優先呼叫
- 如果子類和基類有同名的擴充套件函式,呼叫哪個擴充套件函式由呼叫物件的宣告型別決定
- 除了有擴充套件函式也有擴充套件屬性,不過擴充套件屬性必須要有getter函式,同時也不能初始化
可變引數
fun varargFun(vararg list: Int) { print(list[0]) } fun varargFun2(array: Array<Int>) { listOf(*array) } varargFun(1, 2, 3)
vararg關鍵字表示該引數是可變引數
*關鍵字是展開運算子,在該例中把array展開為多個物件並用於構造list
中綴呼叫
mapOf(1 to "1", 2 to "2", 3 to "3")
這裡的 to 其實就是中綴呼叫,實際上就是一個to函式,中綴呼叫就是把方法名稱放在兩個引數中間,記得空格
我們可以看原始碼infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
其中尖括號裡的是泛型,Pair是一個有兩個成員變數的類(一個叫first一個叫second)
我們先把infix關鍵字蓋住,其實這就是一個擴充套件函式對不對!
我們在加上infix關鍵字,這個擴充套件函式就可以中綴呼叫了
需要注意的是,infix只能用於只有一個引數的函式上
解構宣告
val (para1, para2) = 1 to "1"
在這個例子中,para1就是1,para2就是"1"
其實我們在之前迴圈的章節就有用到過解構宣告
for ((index, value) in list.withIndex()) { print("index = $index and value = $value") }
解構宣告不僅可以用在Pair和List也可以用在Map,我們會在後面的文章中深入瞭解解構規則
字串
var string1 = "\\" var string2 = """\"""
其實string1和string2都是表示
只不過普通的字串包含轉義,\ 就是個轉義字元,所以 \\ 才能代表
而在多重引號字串中就不包含轉義,所以可以直接用 \ 來表示
注:多重引號字串用來寫正則特別方便
區域性函式
這是我最喜歡的語法糖之一:函式裡可以再定義函式
fun outer(){ print("outer invoke") fun inner(){ print("inner invoke") } inner() }
區域性函式中可以訪問外部函式中的所有引數和變數(記得定義在區域性函式之前哦)!
結語
通過本篇文章的學習我們已經算 入門kotlin 了,下篇文章我會寫 類和介面,lambda程式設計以及可空性 相關。基本上這兩篇文章內容熟練掌握就可以應對開發需求,之後會有篇幅講Kotlin的高階使用:反射、泛型等。
最後祝大家國慶Happy~