Kotlin
Java相對(duì)于Kotlin對(duì)比,Java的語(yǔ)法太繁瑣,Kotlin更現(xiàn)代化, 語(yǔ)法更方便簡(jiǎn)潔, 可以作為更好的一個(gè)替代。Kotlin解決了Java中很多的痛點(diǎn),進(jìn)化成一門(mén)優(yōu)秀的語(yǔ)言,給開(kāi)發(fā)者帶來(lái)了更可靠的開(kāi)發(fā)體驗(yàn)。Kotlin可以編譯成Java字節(jié)碼,也可以編譯成JavaScript,方便在沒(méi)有JVM的設(shè)備上運(yùn)行。除此之外Kotlin還可以編譯成二進(jìn)制代碼直接運(yùn)行在機(jī)器上(例如嵌入式設(shè)備或 iOS)。

為什么學(xué)習(xí) Kotlin?
- 2019 年,谷歌I/O 大會(huì)上則宣布 Kotlin 是 Android 應(yīng)用開(kāi)發(fā)的首選語(yǔ)言。
- 簡(jiǎn)潔: 語(yǔ)法簡(jiǎn)潔,大大減少樣板代碼的數(shù)量。
- 安全: 減少應(yīng)用崩潰,避免空指針異常等整個(gè)類(lèi)的錯(cuò)誤。
- 互操作性: 可以和Java互相操作。
其它Kotlin文章
Android學(xué)習(xí)Kotlin之一、常量-條件-函數(shù)-高階函數(shù)
Android學(xué)習(xí)Kotlin之二、Null安全 -字符串操作- 類(lèi)型轉(zhuǎn)換
Android學(xué)習(xí)Kotlin之三、標(biāo)準(zhǔn)庫(kù)函數(shù)-集合List-Set-Map
Android學(xué)習(xí)Kotlin之四、定義類(lèi)-初始化-繼承
Android學(xué)習(xí)Kotlin之五、對(duì)象-接口-抽象類(lèi)
Android學(xué)習(xí)Kotlin之六、泛型-擴(kuò)展函數(shù)
本編文章會(huì)講到的知識(shí)點(diǎn)
- 變量與類(lèi)型
- 數(shù)據(jù)類(lèi)型
- 數(shù)字類(lèi)型
- 變量
- 類(lèi)型推算
- 查看Kotlin字節(jié)碼
- Kotlin的引用類(lèi)型和基本數(shù)據(jù)類(lèi)型
- 條件語(yǔ)句
- if else
- range
- when
- string模板
- 函數(shù)
- 定義函數(shù)
- 函數(shù)參數(shù)
- Unit函數(shù)
- 反引號(hào)中的函數(shù)名
- 高階函數(shù)
- 匿名函數(shù)
- 函數(shù)類(lèi)型與隱式返回
- 匿名函數(shù)參數(shù)
- it關(guān)鍵值
- 類(lèi)型推斷
- 參數(shù)為函數(shù)
- 簡(jiǎn)略傳函數(shù)參
- 函數(shù)引用
- 函數(shù)類(lèi)型作為返回類(lèi)型
- 閉包
- lambda與匿名內(nèi)部類(lèi)
變量與類(lèi)型
數(shù)據(jù)類(lèi)型
kotlin內(nèi)置數(shù)據(jù)類(lèi)型
| 類(lèi)型 | 描述 | 示例 |
|---|---|---|
| String | 字符串 | "Hello kotlin" |
| Char | 單字符 | "A" |
| Boolean | 布爾值 | true\false |
| Number | 數(shù)值 | Byte Short Int Long Float Double |
| Array | 集合 | List Set Map |
數(shù)字類(lèi)型
和java一樣,kotlin中所有的數(shù)字類(lèi)型都是有符號(hào)的,可以有正有負(fù),長(zhǎng)度各不相同。
| 類(lèi)型 | 位 | 最大值 | 最小值 |
|---|---|---|---|
| Byte | 8 | 127 | -128 |
| Short | 16 | 32767 | -32768 |
| Int | 32 | 2147483647 | -2147483648 |
| Long | 64 | 9223372036854775807 | -9223372036854775808 |
| Float | 32 | 3.4028235E38 | 1.4E-45 |
| Double | 64 | 1.7976931348623157E308 | 4 9E-324 |
變量
聲明變量

- var可變變量 可改變值
var age: Int = 18
age++ //可改變
- val只讀變量 只能賦值一次
val name: String = "甜心"
name = "baby" // 會(huì)報(bào)錯(cuò) 使用val定義的變量是不可改變的只能賦值一次
類(lèi)型推算
對(duì)于已聲明并賦值的變量,它允許你省略類(lèi)型定義自動(dòng)推算類(lèi)型
var love = "敲鍵盤(pán)" //自動(dòng)推算類(lèi)型為String
查看Kotlin字節(jié)碼
查看Kotlin編譯后的字節(jié)碼,有助于深入了解Kotlin語(yǔ)言
兩種方式:
- Shift兩次,輸入Show Kotlin
-
Tools>Kotlin>Show Kotlin Bytecode
Kotlin字節(jié)碼
Kotlin的引用類(lèi)型和基本數(shù)據(jù)類(lèi)型
- Java有兩種數(shù)據(jù)類(lèi)型,一種引用類(lèi)型一種基本數(shù)據(jù)類(lèi)型。
- Kotlin只有引用類(lèi)型這一種類(lèi)型,出于更高性能的需要,Kotlin編譯器會(huì)在Java字節(jié)碼中改用基本數(shù)據(jù)類(lèi)型。
條件語(yǔ)句
if else
- java一樣
if (age>18) {
println("成年了")
} else {
println("未成年")
}
- 簡(jiǎn)寫(xiě)方式
println(if (age>18) "已經(jīng)成年2" else "未成年2")
range
Range是Kotlin相對(duì)Java新增的一種表達(dá)式,它表示的是值的范圍,類(lèi)似于數(shù)學(xué)中的區(qū)間。Range的表達(dá)式是像這樣子的:1..20,其中..是運(yùn)算符,它表示一個(gè)閉區(qū)間[1, 20]。而右開(kāi)區(qū)間用until表示:1 until 20,即[1, 20)
- Range表達(dá)式一般是和in和!in操作符一起使用,表示是否包含在該區(qū)間內(nèi)
if (a in 2..10) {//相當(dāng)于 i >= 2 && i <= 20
println("我在區(qū)間")
}
if (a !in 2..10) {//相當(dāng)于 i < 2 && i > 20
println("我不在區(qū)間")
}
- 對(duì)于一些整形的range(IntRange、LongRange、CharRange)是可以進(jìn)行迭代的,它們可以和for循環(huán)一起使用
for (i in 1..6) println(i)//輸出123456
- 使用downTo()函數(shù)可以對(duì)range進(jìn)行倒序迭代
for (i in 6 downTo 1) println(i)//輸出654321
- 使用step()函數(shù),這里指定為2,則每次遍歷后會(huì)以2個(gè)為單位遍歷
for (i in 8..16 step 2) println(i)//輸出8 10 12 14 16
when
when,大家都會(huì)聯(lián)想到 Java 中的 switch,然而在 kotlin 中,when 顯然比 Java 中的 switch 要強(qiáng)大得多。when 既可以被當(dāng)做表達(dá)式使用也可以被當(dāng)做語(yǔ)句使用。如果它被當(dāng)做表達(dá)式。
- 作為表達(dá)式使用,也可以將代碼塊作為我們的分支體,這時(shí)候代碼塊中最后一個(gè)表達(dá)式或者變量就是該分支體的返回結(jié)果
var n = "小芳"
var m = when (n) {
"小明" -> "我是小明"
"小芳" -> {
println("lailai")
"我是小芳芳"
}
"小強(qiáng)" -> "我是小強(qiáng)"
else -> "未知人"
}
println(m)//打印 lailai 我是小芳芳
- 作為語(yǔ)句使用
when (n) {
"小明" -> println("我是小明2")
"小芳" -> println("我是小芳2")
"小強(qiáng)" -> {
println("我是小強(qiáng)2")
}
else -> println("未知人2")
}
- 可以檢測(cè)一個(gè)值在(in)或者不在(!in)一個(gè)區(qū)間或者集合中
when (6) {
in 1..10 -> {
var n = 10
println(n)
}
else -> print(66)
}
- 檢測(cè)一個(gè)值是(is)或者不是(!is)一個(gè)特定類(lèi)型的值,可以直接使用類(lèi)型的屬性和方法
var x = "love"
when (x) {
is String -> println("love長(zhǎng)度= " + x.length)
else -> false
}
- 無(wú)參使用,if else if可以改成這樣
when {
x?.length==4 -> print("長(zhǎng)度對(duì)的")
else -> print("長(zhǎng)度不對(duì)")
}
string模板
模板支持在字符串的引號(hào)內(nèi)放入變量值;還支持字符串里計(jì)算表達(dá)式的值并插入結(jié)果,添加在${}中的任何表達(dá)式,都會(huì)作為字符串的一部分求值。
val man = "沈騰"
val woman ="賈玲"
println("$man love $woman")// 打印 沈騰 love 賈玲
val falg =false
println("我愛(ài)的人是:${if (falg) "鄧紫棋" else "張靚穎"}")//打印 我愛(ài)的人是:張靚穎
函數(shù)
定義函數(shù)
private fun doSomething(age:Int,flag:Boolean) :String{
return "運(yùn)動(dòng)"
}

函數(shù)參數(shù)
- 默認(rèn)值參數(shù)
如果不打算傳入?yún)?shù),可以給參數(shù)設(shè)置默認(rèn)值
private fun setStudent(name:String,age:Int=18){
println("名字:$name , 年齡:$age")
}
setStudent("鄭愷")//沒(méi)有傳age 打印 “名字:鄭愷 , 年齡:18”
setStudent("鄭愷",38)//打印 “名字:鄭愷 , 年齡:38”
- 具名函數(shù)參數(shù)
使用參數(shù)命名值傳參,就不用管函數(shù)中參數(shù)的順序了
private fun setMotion(motion1:String,motion2:String,motion3:String){
println("運(yùn)動(dòng)1:$motion1 , 運(yùn)動(dòng)2:$motion2, 運(yùn)動(dòng)3:$motion3")
}
setMotion(motion2="游泳",motion1 = "乒乓",motion3 = "爬山")// “運(yùn)動(dòng)1:乒乓 , 運(yùn)動(dòng)2:游泳, 運(yùn)動(dòng)3:爬山“
- Unit函數(shù)
Java中沒(méi)有返回值的函數(shù)定義void類(lèi)型,而kotlin沒(méi)有返回值定義Unit返回類(lèi)型,默認(rèn)可以不寫(xiě)。
private fun setStudent(name:String,age:Int=18):Unit{
}
private fun setStudent(name:String,age:Int=18){
}
反引號(hào)中的函數(shù)名
kotlin可以使用空格和特殊字符對(duì)函數(shù)命名,但是函數(shù)名需要用雙引號(hào)括起來(lái)。Kotlin和Java可以互相調(diào)用函數(shù),而kotlin和Java各自有著不同的保留關(guān)鍵字不能作為函數(shù)名,使用反引號(hào)可以解決沖突。
private fun `123`():Int{
return 666
}
private fun `class`():String{
return "class"
}
println(`123`())
println(`class`())
高階函數(shù)
匿名函數(shù)
定義時(shí)不取名字的函數(shù),我們稱(chēng)之為匿名函數(shù),匿名函數(shù)通常整體傳遞給其它函數(shù)或者從其它函數(shù)中返回。
- 定義匿名函數(shù)和調(diào)用, {}是匿名函數(shù) ()是調(diào)用匿名函數(shù)可以傳值 匿名函數(shù)不支持參數(shù)默認(rèn)值和具名函數(shù)參數(shù)。
println({a: Int, b: String ->
"Welcome to HangZhou, $a!(copyright $b)"
}(2021, "磐石"))
- 定義標(biāo)準(zhǔn)庫(kù)中的函數(shù)規(guī)則
//count()函數(shù)是獲取字符個(gè)數(shù)
var totalNum:Int = "missyous".count { letter ->
letter == 's'
}
println("共有s個(gè)數(shù)=:"+totalNum)
函數(shù)類(lèi)型與隱式返回
匿名函數(shù)也有類(lèi)型,匿名函數(shù)可以當(dāng)做變量賦值給函數(shù)類(lèi)型變量,和其它變量一樣,匿名函數(shù)就可以在代碼里傳遞了。函數(shù)類(lèi)型由傳入的參數(shù)和返回值類(lèi)型決定。
匿名函數(shù)一般不需要return關(guān)鍵字來(lái)返回?cái)?shù)據(jù),那么為了返回?cái)?shù)據(jù),匿名函數(shù)會(huì)隱式返回函數(shù)體最后一行語(yǔ)句的結(jié)果。
//定義一個(gè)函數(shù)nowFun返回類(lèi)型是String
val nowFun:()->String
nowFun = {
val name= "西塘河"
"你好 $name"
}
// 簡(jiǎn)寫(xiě)
val nowFun:()->String= {
val name= "西塘河"
"你好 $name"
}
println(nowFun()) // 打印 “你好 西塘河”
匿名函數(shù)參數(shù)
參數(shù)的類(lèi)型放在匿名函數(shù)的類(lèi)型定義中,參數(shù)名則放在函數(shù)定義中
var nowFun2: (String,Int) -> String = {name,age->
"你好 $name 年齡 $age"
}
println(nowFun2("馬云",50))// 打印 “你好 馬云 年齡 50”
it關(guān)鍵值
定義只有一個(gè)參數(shù)匿名函數(shù)時(shí),可以使用it關(guān)鍵字當(dāng)做參數(shù)名,當(dāng)參數(shù)大于1個(gè)時(shí)it就不能用了。
var oneParamFun: (String) -> String = {
"我喜歡:$it"
}
println(oneParamFun("林憶蓮"))// 打印 “我喜歡:林憶蓮”
類(lèi)型推斷
定義一個(gè)函數(shù)變量時(shí),如果已經(jīng)把匿名函數(shù)賦值給了變量,就不用指定變量類(lèi)型里了。有參數(shù)時(shí),匿名函數(shù)的參數(shù)名和類(lèi)型都必須有
//省略前
val typeFun:()->String = {
"我喜歡:"
}
//省略后
val typeFun = {
"我喜歡:"
}
println(typeFun())
//省略前
val typeParamFun:(String,String)->String = { name, yarn ->
"Happy $name $yarn"
}
//省略后
val typeParamFun = { name: String, yarn: String ->
"Happy $name $yarn"
}
println(typeParamFun("彭彭", "2025"))
參數(shù)為函數(shù)
在函數(shù)參數(shù)中可以傳入函數(shù),可以是匿名函數(shù)也可以是普通函數(shù)。
val setTime={goodName:String,yarn:Int->
"$yarn 天貓雙十一 $goodName"
}
fun showTime(name:String, showGood:(String,Int)->String){
val yarn = (2020..2030).shuffled().last()
println(showGood(name,yarn))
}
showTime(name = "關(guān)曉彤",setTime)
簡(jiǎn)略傳函數(shù)參
如果一個(gè)函數(shù)的lambda參數(shù)排在最后或者是唯一的參數(shù),那么括住lambda值的圓括號(hào)就可以省略掉了。
showTime(name = "容祖兒"){goodName:String,yarn:Int->
"$yarn 天貓雙十一 $goodName"
}
函數(shù)引用
上面講過(guò)了 把函數(shù)當(dāng)成參數(shù)傳給一個(gè)函數(shù)使用,不光可以傳遞匿名函數(shù)也可以傳遞具名函數(shù)的引用,只要可以使用lambda表達(dá)式地方都可以使用函數(shù)引用。
fun setStudent(name:String,age:Int):String{
return "我是六年級(jí)的 $name 今年 $age 歲了"
}
fun setClass(name:String,student:(String,Int)->String){
println(student(name,12))
}
setClass("黃曉明", ::setStudent)//打印 “我是六年級(jí)的 黃曉明 今年 12 歲了”
函數(shù)類(lèi)型作為返回類(lèi)型
一個(gè)函數(shù)的返回值可以使一個(gè)函數(shù)(包括匿名函數(shù)和具名函數(shù))。
fun getFruit():(String)->String{
val currYarn = 2021
return {fruitName:String->
"$currYarn 我喜歡吃 $fruitName"
}
}
val fruit = getFruit()//返回的是個(gè)匿名函數(shù)
println(fruit("櫻桃"))// 打印 “2021 我喜歡吃 櫻桃”
閉包
在Kotlin中,匿名好處能夠修改并應(yīng)用定義在自己的作用域之外的變量,匿名函數(shù)引用著定義自身的函數(shù)里的變量,Kotlin中的lambda就是閉包。
能接收函數(shù)或者返回函數(shù)的函數(shù)又叫做高級(jí)函數(shù),高級(jí)函數(shù)廣泛用于函數(shù)式編程當(dāng)中。
lambda與匿名內(nèi)部類(lèi)
為什么要在代碼中使用函數(shù)類(lèi)型?函數(shù)類(lèi)型能讓開(kāi)發(fā)者少寫(xiě)模式化代碼,寫(xiě)出更靈活的代碼。Java8支持lambda表達(dá)式,但不支持將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)或者變量,不過(guò)Java的替代方案是匿名函數(shù)。
- Kotlin使用匿名函數(shù)
kotlin使用匿名內(nèi)部類(lèi)直接創(chuàng)建就行
//定義一個(gè)函數(shù)最后一個(gè)參數(shù)是lamdba匿名函數(shù)
fun setPhone(phoneName: String, moneyDeta: (String, Int) -> Unit) {
val money = if (phoneName == "iphone12") 5800 else 6000
moneyDeta(phoneName, money)
}
// 調(diào)用函數(shù)傳入一個(gè)lamdba匿名函數(shù)
setPhone("iphone12") { phoneName: String, money: Int ->
println("$phoneName 價(jià)格為 $money")
}
- Java中使用匿名函數(shù)
java使用匿名內(nèi)部類(lèi)需要先創(chuàng)建一個(gè)接口
public static void main(String[] args) {
// 通過(guò)new一個(gè)匿名內(nèi)部類(lèi)傳過(guò)去
setPhone("iphone12", new MoneyDeta() {
@Override
public void setMoney(String phoneName, int money) {
System.out.println(phoneName+" 價(jià)格為 "+ money);
}
});
}
public static void setPhone(String phoneName,MoneyDeta moneyDeta){
int money = "iphone12".equals(phoneName)? 5800:6000;
moneyDeta.setMoney(phoneName,money);
}
//定義接口
public interface MoneyDeta{
void setMoney(String phoneName,int money);
}
