前言
kotlin是一種在Java虛擬機上運行的靜態(tài)類型編程語言,由JetBrains設(shè)計開發(fā)并開源。kotlin可以像class文件一樣編譯成Java字節(jié)碼,在JVM上運行,也可以編譯成JavaScript,方便在沒有JVM的設(shè)備上運行。在2017年的Google I/O大會上,Google宣布kotlin成為Android官方開發(fā)語言。
kotlin和Java相比有什么優(yōu)點
(1)代碼簡潔。相比較于Java代碼,kotlin大量使用了高階函數(shù)和lambda語法保證在較少的代碼下實現(xiàn)同等的功能。
(2)非空判斷。在Java中,很容易出現(xiàn)問題或者應(yīng)用程序閃退或者crash的原因很大一部分是因為空指針異常所導(dǎo)致的,而kotlin中則加入了非常友好的非空處理,可以很大程度上避免出現(xiàn)由于非空導(dǎo)致程序在運行過程中出現(xiàn)的異常。
(3)kotlin特有的擴展屬性,不再需要Java工具類,對開發(fā)者而言更加友好。
(4)跨平臺。kotlin不僅支持生成.class文件運行在JVM上,同樣也支持生成JavaScript運行在沒有JVM支持的設(shè)備上。
當(dāng)然,kotlin的優(yōu)點不僅僅只是這些,還有很多其他的有待我們發(fā)現(xiàn),既然Google 官方早在幾年前就將它作為Android開發(fā)的官方語言,必然有它的道理,所以,接下來我們就一起來看看kotlin到底有什么魅力吧。
語法
kotlin的語法在很大程度上和Java類似,所以對于Java老司機來說,學(xué)習(xí)kotlin是很容易的事情,Java語言以.class作為文件結(jié)尾,而在kotlin中以.kt作為結(jié)尾。
變量(常量)定義
var <標(biāo)識符> : <類型> = <初始化值>
// val 關(guān)鍵字,只能賦值一次的變量(類似Java中final修飾的變量)
var <標(biāo)識符> : <類型> = <初始化值>
無論是變量還是常量都可以沒有初始化值,但是需要注意的是,在聲明的變量或者常量作為類里面的全局使用的時候必須進行初始化操作,否則會報錯,而在函數(shù)里面則非必需。

需要強調(diào)的是,在Java中,聲明變量或者常量需要顯性的告知所歸屬的類型,而在kotlin中則無效顯示,可交給編譯器進行判斷
var x = 5 // 系統(tǒng)自動推斷變量類型為Int
const關(guān)鍵字
在Kotlin中通過val定義的變量,只有g(shù)et方法,沒有set方法,所以只能讀不能寫。但是其get方法可以復(fù)寫,從而造成val定義的變量,有可能會發(fā)生值變化。所以針對這個問題,我們需要采用const關(guān)鍵字。在Kotlin中除了val關(guān)鍵字定義一個常量外,還提供了一個const關(guān)鍵字標(biāo)識一個常量。const修飾的val變量相當(dāng)于java中 static final是真正意義上的java常量。但是在實際編碼中我們無法直接使用const val,而必須得這樣寫
// companion object類似于Java的static
companion object {
const val C : Int = 0
}
函數(shù)定義
函數(shù)定義使用關(guān)鍵字 fun,參數(shù)格式為:參數(shù) : 類型
fun sum(a: Int, b: Int): Int { // Int 參數(shù),返回值 Int
return a + b
}
public fun sum(a: Int, b: Int): Int = a + b // public 方法則必須明確寫出返回類型
// Unit的可以不寫,系統(tǒng)默認(rèn)的就是Unit
fun printSum(a: Int, b: Int): Unit {
print(a + b)
}
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
// 測試
fun main(args: Array<String>) {
vars(1,2,3,4,5) // 輸出12345
}
fun main(args: Array<String>) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 輸出 3
}
注釋
// 這是一個單行注釋
/* 這是一個多行的
塊注釋。 */
字符串模板
$ 表示一個變量名或者變量值
$varName 表示變量值
${varName.fun()} 表示變量的方法返回值
var a = 1
// 模板中的簡單名稱:
val s1 = "a is $a"
a = 2
// 模板中的任意表達式:
val s2 = "${s1.replace("is", "was")}, but now is $a"
NULL檢查機制
kotlin的空安全設(shè)計對于聲明可為空的參數(shù),在使用時候要進行空判斷處理,處理的方式有兩種:
(1)字段后加!!像Java一樣拋出異常。
(2)字段后加?在值為空的時候不做處理直接返回null或者配合?:做空判斷處理。
//類型后面加?表示可為空
var age: String? = "23"
//拋出空指針異常
val ages = age!!.toInt()
//不做處理返回 null
val ages1 = age?.toInt()
//age為空返回-1
val ages2 = age?.toInt() ?: -1
類型檢測及自動類型轉(zhuǎn)換
我們可以使用 is 運算符檢測一個表達式是否某類型的一個實例(類似于Java中的instanceof關(guān)鍵字)。
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// 做過類型判斷以后,obj會被系統(tǒng)自動轉(zhuǎn)換為String類型
return obj.length
}
區(qū)間
區(qū)間表達式由具有操作符形式 .. 的 rangeTo 函數(shù)輔以 in 和 !in 形成。
for (i in 1..4) print(i) // 輸出“1234”
for (i in 4..1) print(i) // 什么都不輸出,因為在使用in的時候必須保證前面的數(shù)字小于后面的數(shù)字
if (i in 1..10) { // 等同于 1 <= i && i <= 10
println(i)
}
// 使用 step 指定步長
for (i in 1..4 step 2) print(i) // 輸出“13”
for (i in 4 downTo 1 step 2) print(i) // 輸出“42”
// 使用 until 函數(shù)排除結(jié)束元素
for (i in 1 until 10) { // i in [1, 10) 排除了 10
println(i)
}
需要強調(diào)的是,使用 ../downTo 既包前又包后,使用 until 只包前不包后
基本數(shù)據(jù)類型
kotlin的基本數(shù)值類型包括Byte、Short、Int、Long、Float、Double 等。不同于 Java 的是,字符不屬于數(shù)值類型,是一個獨立的數(shù)據(jù)類型。
| 類型 | 位寬度 |
|---|---|
| Double | 64 |
| Long | 64 |
| Float | 32 |
| Int | 32 |
| Short | 16 |
| Byte | 8 |
除此之外,還有
boolean:
boolean數(shù)據(jù)類型表示一位的信息;
只有兩個取值:true 和 false;
這種類型只作為一種標(biāo)志來記錄 true/false 情況;
默認(rèn)值是 false;
例子:boolean one = true。
char:
char 類型是一個單一的 16 位 Unicode 字符;
最小值是 \u0000(十進制等效值為 0);
最大值是 \uffff(即為 65535);
char 數(shù)據(jù)類型可以儲存任何字符;
例子:char letter = 'A';。
Kotlin 中沒有基礎(chǔ)數(shù)據(jù)類型,只有封裝的數(shù)字類型,你每定義的一個變量,其實 Kotlin 幫你封裝了一個對象,這樣可以保證不會出現(xiàn)空指針。數(shù)字類型也一樣,所以在比較兩個數(shù)字的時候,就有比較數(shù)據(jù)大小和比較兩個對象是否相同的區(qū)別了。在 Kotlin 中,三個等號 === 表示比較對象地址,兩個 == 表示比較兩個值大小。
fun main(args: Array<String>) {
val a: Int = 10000
println(a === a) // true,值相等,對象地址相等
//經(jīng)過了裝箱,創(chuàng)建了兩個不同的對象
val boxedA: Int? = a
val anotherBoxedA: Int? = a
//雖然經(jīng)過了裝箱,但是值是相等的,都是10000
println(boxedA === anotherBoxedA) // false,值相等,對象地址不一樣
println(boxedA == anotherBoxedA) // true,值相等
}
類型轉(zhuǎn)換
每種數(shù)據(jù)類型都有下面的這些方法,可以轉(zhuǎn)化為其它的類型:
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
位操作符
對于Int和Long類型,還有一系列的位操作符可以使用,分別是:
shl(bits) – 左移位 (Java’s <<)
shr(bits) – 右移位 (Java’s >>)
ushr(bits) – 無符號右移位 (Java’s >>>)
and(bits) – 與
or(bits) – 或
xor(bits) – 異或
inv() – 反向
實際上,在開發(fā)過程中,我們使用到的較多的是and、or這兩個
數(shù)組
數(shù)組用類 Array 實現(xiàn),并且還有一個 size 屬性及 get 和 set 方法,由于使用 [] 重載了 get 和 set 方法,所以我們可以通過下標(biāo)很方便的獲取或者設(shè)置數(shù)組對應(yīng)位置的值。
fun main(args: Array<String>) {
//[1,2,3]
val a = arrayOf(1, 2, 3)
//[0,2,4]
val b = Array(3, { i -> (i * 2) })
//讀取數(shù)組內(nèi)容
println(a[0]) // 輸出結(jié)果:1
println(b[1]) // 輸出結(jié)果:2
}
條件控制
IF 表達式
一個 if 語句包含一個布爾表達式和一條或多條語句。
// 傳統(tǒng)用法
var max = a
if (a < b) max = b
// 使用 else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// 作為表達式
val max = if (a > b) a else b
我們也可以把 IF 表達式的結(jié)果賦值給一個變量。
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
When 表達式
when 將它的參數(shù)和所有的分支條件順序比較,直到某個分支滿足條件。
when 既可以被當(dāng)做表達式使用也可以被當(dāng)做語句使用。如果它被當(dāng)做表達式,符合條件的分支的值就是整個表達式的值,如果當(dāng)做語句使用, 則忽略個別分支的值。
when 類似其他語言的 switch 操作符。其最簡單的形式如下:
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意這個塊
print("x 不是 1 ,也不是 2")
}
}
但是相比較Java的switch而言,when更加強大,它不僅能滿足同一個類型的條件判斷,同時還能滿足多種類型的判斷
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
循環(huán)控制
For循環(huán)
for 循環(huán)可以對任何提供迭代器(iterator)的對象進行遍歷,語法如下:
// 遍歷對象
for (item in collection) print(item)
// 通過索引遍歷
for (i in array.indices) {
print(array[i])
}
// 同步獲取key和value
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
while和do...while循環(huán)
while是最基本的循環(huán),它的結(jié)構(gòu)為:
while( 布爾表達式 ) {
//循環(huán)內(nèi)容
}
do…while 循環(huán)對于 while 語句而言,如果不滿足條件,則不能進入循環(huán)。但有時候我們需要即使不滿足條件,也至少執(zhí)行一次。
do…while 循環(huán)和 while 循環(huán)相似,不同的是,do…while 循環(huán)至少會執(zhí)行一次。
返回和跳轉(zhuǎn)
Kotlin 有三種結(jié)構(gòu)化跳轉(zhuǎn)表達式:
(1)return。默認(rèn)從最直接包圍它的函數(shù)或者匿名函數(shù)返回。
(2) break。終止最直接包圍它的循環(huán)。
(3) continue。繼續(xù)下一次最直接包圍它的循環(huán)。
fun main(args: Array<String>) {
for (i in 1..10) {
if (i==3) continue // i 為 3 時跳過當(dāng)前循環(huán),繼續(xù)下一次循環(huán)
println(i)
if (i==4)return // i 為 4 時 結(jié)束運行的函數(shù)
if (i>7) break // i 為 8 時 跳出循環(huán)
}
}
這里需要強調(diào)的是,很多時候盡管return和break看起來差不多,其實二者完全不是一個概念,break更多的是作用在中斷循環(huán),而return則是直接結(jié)束當(dāng)前函數(shù)。
Break 和 Continue 標(biāo)簽
在 Kotlin 中任何表達式都可以用標(biāo)簽(label)來標(biāo)記。 標(biāo)簽的格式為標(biāo)識符后跟 @ 符號,例如:abc@、fooBar@都是有效的標(biāo)簽。 要為一個表達式加標(biāo)簽,我們只要在其前加標(biāo)簽即可。
loop@ for (i in 1..100) {
for (j in 1..100) {
if (……) break@loop // 代表直接跳出被標(biāo)記為loop的for循環(huán)
}
}
關(guān)于kotlin的基礎(chǔ)篇到這里就到一段落了,下一篇我們就開始進入到類文件,繼續(xù)來看看kotlin的魅力。