Kotlin基礎語法
文章目錄
- Kotlin基礎語法
- 1.包
- 2.宣告變數和值
- 3.變數型別推斷
- 4.字串與其模板運算式
- 5.流程控制陳述句
- 6.代碼注釋
- 7.語法與識別符號
- .修飾符
- .關鍵字
- .運算子
- .擴展函式和擴展屬性
- .空指標安全
- .標準庫API簡介
1.包
比如說 程式員A寫了一個類叫JSON,程式員B也寫了一個類叫JSON,然后我們寫代碼的時候想要同時使用這兩個類,該怎么區分呢?一個答案是使用目錄命名空間,對應在java中就是使用包(package)來組織類,以確保類名的唯一性,上面說的例子,A寫的類放到package com.abc.fastjson中 ,B寫的類就放到package com.bbc.jackjson中,這樣我們在代碼中,就可以根據命名空間來分別使用這兩個類,呼叫如下:
com.abc.fastjson.JSON.toJSONString();
com.bbc.jackjson.JSON.parseJSONObject();
kotlin也沿襲了Java的package概念,同時做了些擴展
我們可以在*.kt檔案開頭宣告package命名空間,例如在PackageDemo.kt源代碼中,我們按照如下方式宣告包:
package com.easy.kotlin
fun what(){
println("This is WHAT ?")
}
class Motorbike{
fun drive(){
println("Drive the Motorbike ...")
}
}
fun main(args:Array<String>){
println("Hello,World!")
}
包的宣告處于源檔案頂部,這里,我們宣告了包com.easy.kotlin,里面定義了包級函式what(),同時定義了一個類Motorbike,另外,目錄與包的結構 無需匹配:源代碼可以在檔案系統的任意位置,
2.宣告變數和值
首先,在Kotlin中,一切都是物件,所以,所有變數也都是物件(也就是說,任何變數都是根據參考型別來使用的),
Kotlin的變數分為var(可變的) 和 val(不可變的),可以簡單的理解為:
var是可寫的,在它生命周期中可以被多次賦值
val是只讀的,僅能一次賦值,后面就不能被重新賦值
3.變數型別推斷
- 省去變數型別 在Kotlin中,大部分情況下不需要說明你使用物件的型別,編譯器可以直接推斷出它的型別代碼如下:
fun typeInference(){
val str = "abc"
println(str) //輸出abc
println(str is String) //true
println(str::class) //class java.lang.String(Kotlin reflection is not available)
println(str::class.java) //class java.lang.String
}
所以,我們只需要依據要產生的變數型別填寫var或val,其型別通常能夠被推斷出來,編譯器能夠檢測其型別,自動完成型別轉換,當然,我們也可以明確地指定變數型別,但是型別推斷不是所有的,例如,整形變數Int不能賦值Long變數,下面的代碼不能通過編譯
fun Int2Long(){
val x:Int = 10
val y:Long = x //Type mismatch
val y: Long = x.toLong()
}
- 使用is運算子進行型別檢測 is運算子檢測一個運算式是否為某型別的一個實體,如果一個不可變的區域變數或屬性已經判斷為某型別,那么檢測厚的分支中可以直接當作該型別使用,無需顯式轉換:
fun getLength(obj: Any): Int? {
var result = 0
if(obj is String){
//'obj'在該條件分支自動轉換成‘String'
println(obj::class) // class java.lang.String
result = obj.length
println(result)
}
//在離開型別檢測分支后,‘obj'仍然是‘Any'型別
println(obj::class) //class java.lang.Object
return result
}
4.字串與其模板運算式
原始字串(raw string)由三重引號(""")分隔(這個跟python一樣),原始字串可以包含換行符和任何其他字符
package com.easy.kotlin
fun main(args: Array<String>){
val rawString = """
fun helloWorld(val name : String){
println("Hello,world!")
}
"""
println(rawString)
}
字串可以包含模板運算式,模板運算式以美元符號($)開始:
val fooTemplateString = "$rawString has ${rawString.length} characters"
println(fooTemplateString)
5.流程控制陳述句
流程控制陳述句是編程中的核心之一,一般可以分為如下三類
- 分支陳述句(if,when) if-else陳述句是控制程式流程的最基本形式,其中 else可選,在Kotlin中,if是一個運算式,即它會回傳一個值
代碼示例如下:
package com.easy.kotlin
fun main(args: Array<String>){
println(max(1,2))
}
fun max(a: Int,b: Int): Int{
//作為運算式
val max = if (a > b) a else b
return max // return if ( a > b) a else b
}
fun max1 (a: Int,b:Int): Int{
//傳統用法
var max1 = a
if( a < b) max1 = b
retrun max1
}
fun max2(a: Int,b: Int) : Int{
//With else
var max2: Int
if(a > b){
max2 = a
} else {
max2 =b
}
return max2
}
另外,if的分支可以是代碼塊,最后的運算式作為該塊的值
fun max3(a: Int,b: Int): Int{
val max = if(a > b){
print("Max is a")
a
} else {
print("Max is b")
b
}
return max
}
if作為代碼塊時,最后一行為其回傳值
另外,在Kotlin中沒有類似true?1:0這樣的三元運算式,對應的寫法是使用if else 陳述句:
if(true) 1 else 0
如果if運算式只有一個分支,或者分支的結果是Unit,它的值就是Unit
示例如下:
>>> val x = if(1==1) true
>>> x
kotlin.Unit
>>> val y = if(1==1) true else false
>>> y
true
if-else 陳述句規則
1)if后的括號不能省略,括號里的運算式的值必須是布爾型
2)如果條件體內只有一條陳述句需要執行,那么if后面的大括號可以省略,良好的編程風格建議加上大括號
3)對于給定的if,else陳述句是可選的,else if陳述句也是可選的,else 和 else if 同時出現時,else 必須出現在 else if之后
4)else 和 else if 同時出現時,else 必須出現在 else if之后
5)如果有多條else if陳述句同時出現,那么如果有一條else if陳述句的運算式測驗成功,那么會忽略掉其他所有else if和else的分支
6)如果出現多個if ,只有一個else 的情形,else子句歸屬于最內層的if陳述句,這些規則跟Java ,C語言基本相同,
- when運算式 when運算式類似于 switch-case運算式, when會對所有的分支進行檢查,直到有一個條件滿足為止,但相比switch-case而言,when的陳述句更加強大,靈活,Kotlin的極簡語法表達風格,使得我們對分支檢查的代碼寫起來更加簡單直接:
fun cases (obj: Any){
when(obj){
1->print("第一項")
"hello" - >print("這個是字串hello")
is Long->print("這是一個Long型別資料")
! is String->print("這不是String型別的資料“)
else -> print("else 類似于Java中的default")
}
}
像if一樣,when的每一個分支也可以是一個代碼塊,它的值是塊中最后的運算式的值,如果其他分支都不滿足條件,則會到else分支(類似default),如果我們有很多分支需要用相同的方式處理,則可以把多個條件分支條件放在一起,用逗號分隔:
fun switch(x: Any){
when(x){
-1,0 -> print("x == -1 or x == 0 ")
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
}
可以用任意運算式(而不只是常量)作為分支條件
fun switch(x: Int){
val s = "123"
when(x){
-1,0 -> print("x == 1 or x ==0")
1 -> print("x == 1")
2 -> print("x == 2")
8 -> print("x is 8")
parseInt(s) -> println("x is 123")
else -> {
print("x is neither 1 nor 2")
}
}
}
也可以檢測一個值在(in)或者不在(!in)一個區間或者集合中:
val x = 1
val validNumbers = arrayOf(1,2,3)
when(x){
in 1..10 -> print("x is in the range")
in vaildNumbers -> print("x is valid")
!in 10..20 ->print("x is outside the range")
else -> {
print("none of the above")
}
}
-
回圈陳述句(for,while)Kotlin的for回圈與現代的程式設計語言基本相同,這里就不做過多介紹了
-
break和continue 與現代的程式設計語言基本相同,這里就不做過多介紹了
-
return 在Kotlin中,除了運算式的值,回傳值的函式都要求顯示地使用return來回傳其值
fun sum(a: Int,b: Int): Int{
return a + b
}
fun max(a: Int,b: Int): Int { if (a > b) return a else return b}
在Kotlin中,可以直接使用=符號來直接回傳一個函式的值
代碼示例如下:
>>> fun sum(a: Int,b: Int) = a + b
>>> fun max(a: Int,b: Int) = if (a > b) a else b
>>> sum(1,10)
11
>>> max(1,2)
2
>>> val sum =fun(a:Int,b:Int) = a+b
>>> sum
(kotlin.Int,kotlin.Int) -> kotlin.Int
>>> sum(1,1)
2
>>> val sumf = fun(a:Int,b:Int) = {a+b}
>>> sumf
(kotlin.Int,kotlin.Int) -> () -> kotlin.Int
>>> sumf(1,1)
() -> kotlin.Int
>>> sumf(1,1).invoke()
2
上述代碼示例中,我們可以看到,后面的函式體陳述句有沒有大括號{}意思完全不同,加了大括號,意義就完全不一樣了,通過下面的代碼示例可以清晰的看出:
>>> fun sumf(a:Int,b:Int) = {a+b}
>>> sumf(1,1)
()->kotlin.Int
>>> sumf(1,1).invoke
error: function invocation 'invoke()' expected
sumf(1,1).invoke
>>> sumf(1,1).invode()
2
>>> fun maxf(a:Int,b:Int) = {if(a>b) a else b}
>>> maxf(1,2)
() -> kotlin.Int
>>> maxf(1,2).invoke()
2
可以看出,sumf,max的回傳值是函式型別
() -> kotlin.Int
() -> kotlin.Int
這點跟Scala是不同的,在Scala中,帶不帶大括號{}意思都一樣
Kotlin中return陳述句 會從最近的函式或匿名函式中回傳,但是在Lambda運算式中遇到return ,則直接回傳最近的外層函式,例如如下面兩個函式是不同的:
fun returnDemo_1(){
println(" START " + ::returnDemo_1.name)
val intArray = intArrayOf(1,2,3,4,5)
intArray.forEach(){
if(it == 3) return
println(it)
}
println(" END " + ::returnDemo_1.name)
}
//1
//2
fun returnDemo_2(){
println(" START " + ::returnDemo_2.name)
val intArray = intArrayOf(1,2,3,4,5)
intArray.forEach(fun(a: Int) {
if(a == 3) return
println(a)
})
println(" END " + ::returnDemo_2.name)
}
//1
//2
//4
//5
returnDemo_1在遇到3時會直接回傳(有點類似回圈體中的break行為),最后輸出為: 1 , 2
returnDemo_2在遇到3時會跳過它繼續執行(有點類似回圈體中的continue行為),最后輸出為:1 ,2 ,4 ,5
在returnDemo_2中,我們用一個匿名函式替代lambda運算式,匿名函式內部的return陳述句將從該匿名函式自身回傳
在Kotlin中這是匿名函式和lambda運算式行為不一致的地方,當然,為了顯示地指明return回傳的地址,為此Kotlin還提供了@Label(標簽)來控制回傳陳述句,且看下節分解,
- 標簽 在Kotlin中任何運算式都可以用標簽(label)來標記,標簽的格式為識別符號后跟@符合,例如abc@,jarOfLove@都是有效的標簽,我們可以用Label標簽來控制return ,break 或continue的跳轉(jump)行為,
Kotlin的函式是可以被嵌套的,它有函式字面量,區域函式等,有了標簽限制的return,我們就可以從外層函式回傳了,例如,從lambda運算式中回傳,returnDemo_2()我們可以顯示地制定lambda運算式中的return地址是其入口處,
代碼示例如下:
fun returnDemo_3(){
println(" START " + ::returnDemo_3.name)
val intArray = intArrayOf(1,2,3,4,5)
intArray.forEach here@{
if(it == 3) return @here//指令跳轉到 lambda運算式標簽here@ 處,
println(it)
}
println(" END " + ::returnDemo_3.name)
}
//1
//2
//4
//5
我們在lambda運算式開頭處添加了標簽here@,可以這么理解:該標簽相當于是記錄了lambda運算式的指令執行入口地址,然后在運算式內部使用return@here跳轉至lambda運算式該地址處,另外,也可以使用隱式標簽更方便,該標簽與接收該lambda的函式同名,
代碼示例如下:
fun returnDemo_4(){
println(" START " + ::returnDemo_4.name)
val intArray = intArrayOf(1,2,3,4,5)
intArray.forEach {
if(it == 3){
return@forEach //從lambda運算式@forEach中回傳,
println(it)
}
}
println(" END " + ::returnDemo_4.name)
}
- throw運算式
在Kotlin中throw是運算式,它的型別是特殊型別:Nothing,該型別沒有值,與C,Java中的void意思一樣:
>>> Nothing::class
class java.lang.Void
我們在代碼中,用Nothing來標記無回傳的函式:
>>> fun fail(msg:String):Nothing{ throw IllegalArgumentException(msg)}
>>> fail("XXXX")
java.lang.IllegalArgumentException: XXXX
at Line57.fail(Unknown Source)
另外,如果把一個throw運算式的值賦值給一個變數,需要顯示宣告型別為Nothing:
>>> val ex = throw Exception("YYYYYYYY")
error: 'Nothing' property type needs to be specified explicity
val ex = throw Exception("YYYYYYYY")
>>> val ex:Nothing = throw Exception("YYYYYYYY")
java.lang.Exception: YYYYYYYY
另外,因為ex變數是Nothing型別,沒有任何值,所以無法當作引數傳給函式
6.代碼注釋
正如Java和JavaScript ,Kotlin支持行注釋及塊注釋
//這是一個行注釋
/× 這是一個多行的
塊注釋 ×/
與Java不同的是,Kotlin的塊注釋可以嵌套,就是說,你可以這樣注釋:

7.語法與識別符號
我們知道,任何一門語言都會有一些自己專用的關鍵字,符號以及規定的語法規則等等,程式員們使用這些基礎詞匯和語法規則來表達演算法步驟,也就是寫代碼的程序,
詞法分析是編譯器對原始碼進行編譯的基礎步驟之一,詞發分析是將源程式讀入的字符序列,按照一定的規則轉換成詞法單元(Token)序列的程序,詞法單元是語言中具有獨立意義的最小單元,包括修飾符,關鍵字,常數,運算子,等等
.修飾符
在kotlin原始碼專案中 kotlin/grammar/src/modifiers.grm檔案中,描述了Kotlin語言的修飾符:modifiers:(modifier | annotations) * ; typeModifiers:(suspendModifier | annotations)*;
modifier : classModifier
:accessModifier
:varianceAnnotation
:memberModifier
:parameterModifier
:typeParameterModifier
:functionModifier
:propertyModifier
classModifier 類修飾符
: "abstract"抽象類
: “final” 不可被繼承final類
: "enum"列舉類
: "open"可繼承open類
: "annotation"注解類
: "sealed"密封類
: "data"資料類
memberModifier
: "override"重寫函式
: "open"可被重寫
: "final"不可被重寫
: "abstract"抽象函式
: "lateinit"后期初始化
accessModifier 訪問控制權限 默認public
: “private”
: “protected”
: “public”
: “internal”
其中,internel訪問權限,指的是整個模塊內可訪問,模塊(module)是指一起編譯的一組Kotlin原始碼代碼檔案:例如,InteliJ IDEA模塊,Maven專案 或者Gradle專案,通過Ant任務的一次呼叫編譯的一組檔案等,
.關鍵字
每一門語言都有自己的關鍵字集合,在Kotlin中,這些關鍵字定義如下:

this 關鍵字的使用場景 1.在類的成員中,this指向的是該類的當前物件 2.在擴展函式或者帶接收者的函式字面值中,this表示在點左側傳遞的接收者引數 3.如果this沒有限定符,它指的是最內層的包含它的作用域,
super關鍵字 持有指向其父類的參考
.運算子
這里重點介紹Elvis運算子? 在Kotlin中 Elvis運算子特定是跟null比較,主要用來做null安全性檢查 也就是說 y =x?:0 等價于 val y = if(x !== null) x else 0
Elvis 運算子? 是一個二元運算子,如果第一個運算元為真,則回傳第一個運算元,否則將計算并回傳其第二個運算元,它是三元條件運算子的變體,
.擴展函式和擴展屬性
Kotlin支持擴展函式和擴展屬性,能夠擴展一個類的新功能而無需繼承該類或使用像裝飾者這樣的設計模式等
.空指標安全
Java最大的一個問題是 null, 這個問題Kotlin針對Java做了改進,它使用了顯式的null,這會強制我們在必要時進行null檢查,Kotlin通過型別系統中的可空型別來實作空指標的安全檢查,關于Kotlin的可空型別以及型別系統將在下章介紹,
.標準庫API簡介
具體參考:http://kotlinlang.org/api/latest/jvm/stdlib/index.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/289442.html
標籤:其他
