Kotlin
Java相對于Kotlin對比奕扣,Java的語法太繁瑣掌敬,Kotlin更現(xiàn)代化, 語法更方便簡潔, 可以作為更好的一個(gè)替代奔害。Kotlin解決了Java中很多的痛點(diǎn)华临,進(jìn)化成一門優(yōu)秀的語言雅潭,給開發(fā)者帶來了更可靠的開發(fā)體驗(yàn)。Kotlin可以編譯成Java字節(jié)碼筛圆,也可以編譯成JavaScript,方便在沒有JVM的設(shè)備上運(yùn)行轰绵。除此之外Kotlin還可以編譯成二進(jìn)制代碼直接運(yùn)行在機(jī)器上(例如嵌入式設(shè)備或 iOS)左腔。
為什么學(xué)習(xí) Kotlin液样?
- 2019 年鞭莽,谷歌I/O 大會(huì)上則宣布 Kotlin 是 Android 應(yīng)用開發(fā)的首選語言麸祷。
- 簡潔: 語法簡潔阶牍,大大減少樣板代碼的數(shù)量。
- 安全: 減少應(yīng)用崩潰琳状,避免空指針異常等整個(gè)類的錯(cuò)誤盒齿。
- 互操作性: 可以和Java互相操作县昂。
其它Kotlin文章
Android學(xué)習(xí)Kotlin之一倒彰、常量-條件-函數(shù)-高階函數(shù)
Android學(xué)習(xí)Kotlin之二待讳、Null安全 -字符串操作- 類型轉(zhuǎn)換
Android學(xué)習(xí)Kotlin之三、標(biāo)準(zhǔn)庫函數(shù)-集合List-Set-Map
Android學(xué)習(xí)Kotlin之四痴晦、定義類-初始化-繼承
Android學(xué)習(xí)Kotlin之五誊酌、對象-接口-抽象類
Android學(xué)習(xí)Kotlin之六碧浊、泛型-擴(kuò)展函數(shù)
本編文章會(huì)講到的知識點(diǎn)
- 變量與類型
- 數(shù)據(jù)類型
- 數(shù)字類型
- 變量
- 類型推算
- 查看Kotlin字節(jié)碼
- Kotlin的引用類型和基本數(shù)據(jù)類型
- 條件語句
- if else
- range
- when
- string模板
- 函數(shù)
- 定義函數(shù)
- 函數(shù)參數(shù)
- Unit函數(shù)
- 反引號中的函數(shù)名
- 高階函數(shù)
- 匿名函數(shù)
- 函數(shù)類型與隱式返回
- 匿名函數(shù)參數(shù)
- it關(guān)鍵值
- 類型推斷
- 參數(shù)為函數(shù)
- 簡略傳函數(shù)參
- 函數(shù)引用
- 函數(shù)類型作為返回類型
- 閉包
- lambda與匿名內(nèi)部類
變量與類型
數(shù)據(jù)類型
kotlin內(nèi)置數(shù)據(jù)類型
類型 | 描述 | 示例 |
---|---|---|
String | 字符串 | "Hello kotlin" |
Char | 單字符 | "A" |
Boolean | 布爾值 | true\false |
Number | 數(shù)值 | Byte Short Int Long Float Double |
Array | 集合 | List Set Map |
數(shù)字類型
和java一樣,kotlin中所有的數(shù)字類型都是有符號的驹止,可以有正有負(fù)臊恋,長度各不相同捞镰。
類型 | 位 | 最大值 | 最小值 |
---|---|---|---|
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定義的變量是不可改變的只能賦值一次
類型推算
對于已聲明并賦值的變量践樱,它允許你省略類型定義自動(dòng)推算類型
var love = "敲鍵盤" //自動(dòng)推算類型為String
查看Kotlin字節(jié)碼
查看Kotlin編譯后的字節(jié)碼拷邢,有助于深入了解Kotlin語言
兩種方式:
- Shift兩次瞭稼,輸入Show Kotlin
-
Tools>Kotlin>Show Kotlin Bytecode
Kotlin字節(jié)碼
Kotlin的引用類型和基本數(shù)據(jù)類型
- Java有兩種數(shù)據(jù)類型环肘,一種引用類型一種基本數(shù)據(jù)類型悔雹。
- Kotlin只有引用類型這一種類型欣喧,出于更高性能的需要唆阿,Kotlin編譯器會(huì)在Java字節(jié)碼中改用基本數(shù)據(jù)類型驯鳖。
條件語句
if else
- java一樣
if (age>18) {
println("成年了")
} else {
println("未成年")
}
- 簡寫方式
println(if (age>18) "已經(jīng)成年2" else "未成年2")
range
Range是Kotlin相對Java新增的一種表達(dá)式浅辙,它表示的是值的范圍摔握,類似于數(shù)學(xué)中的區(qū)間丁寄。Range的表達(dá)式是像這樣子的:1..20伊磺,其中..是運(yùn)算符屑埋,它表示一個(gè)閉區(qū)間[1, 20]。而右開區(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ū)間")
}
- 對于一些整形的range(IntRange峻黍、LongRange拨匆、CharRange)是可以進(jìn)行迭代的惭每,它們可以和for循環(huán)一起使用
for (i in 1..6) println(i)//輸出123456
- 使用downTo()函數(shù)可以對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)做語句使用希太。如果它被當(dāng)做表達(dá)式。
- 作為表達(dá)式使用,也可以將代碼塊作為我們的分支體酝蜒,這時(shí)候代碼塊中最后一個(gè)表達(dá)式或者變量就是該分支體的返回結(jié)果
var n = "小芳"
var m = when (n) {
"小明" -> "我是小明"
"小芳" -> {
println("lailai")
"我是小芳芳"
}
"小強(qiáng)" -> "我是小強(qiáng)"
else -> "未知人"
}
println(m)//打印 lailai 我是小芳芳
- 作為語句使用
when (n) {
"小明" -> println("我是小明2")
"小芳" -> println("我是小芳2")
"小強(qiáng)" -> {
println("我是小強(qiáng)2")
}
else -> println("未知人2")
}
- 可以檢測一個(gè)值在(in)或者不在(!in)一個(gè)區(qū)間或者集合中
when (6) {
in 1..10 -> {
var n = 10
println(n)
}
else -> print(66)
}
- 檢測一個(gè)值是(is)或者不是(!is)一個(gè)特定類型的值誊辉,可以直接使用類型的屬性和方法
var x = "love"
when (x) {
is String -> println("love長度= " + x.length)
else -> false
}
- 無參使用,if else if可以改成這樣
when {
x?.length==4 -> print("長度對的")
else -> print("長度不對")
}
string模板
模板支持在字符串的引號內(nèi)放入變量值亡脑;還支持字符串里計(jì)算表達(dá)式的值并插入結(jié)果堕澄,添加在${}中的任何表達(dá)式邀跃,都會(huì)作為字符串的一部分求值。
val man = "沈騰"
val woman ="賈玲"
println("$man love $woman")// 打印 沈騰 love 賈玲
val falg =false
println("我愛的人是:${if (falg) "鄧紫棋" else "張靚穎"}")//打印 我愛的人是:張靚穎
函數(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("鄭愷")//沒有傳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中沒有返回值的函數(shù)定義void類型坑傅,而kotlin沒有返回值定義Unit返回類型丽涩,默認(rèn)可以不寫。
private fun setStudent(name:String,age:Int=18):Unit{
}
private fun setStudent(name:String,age:Int=18){
}
反引號中的函數(shù)名
kotlin可以使用空格和特殊字符對函數(shù)命名裁蚁,但是函數(shù)名需要用雙引號括起來矢渊。Kotlin和Java可以互相調(diào)用函數(shù),而kotlin和Java各自有著不同的保留關(guān)鍵字不能作為函數(shù)名枉证,使用反引號可以解決沖突矮男。
private fun `123`():Int{
return 666
}
private fun `class`():String{
return "class"
}
println(`123`())
println(`class`())
高階函數(shù)
匿名函數(shù)
定義時(shí)不取名字的函數(shù),我們稱之為匿名函數(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)庫中的函數(shù)規(guī)則
//count()函數(shù)是獲取字符個(gè)數(shù)
var totalNum:Int = "missyous".count { letter ->
letter == 's'
}
println("共有s個(gè)數(shù)=:"+totalNum)
函數(shù)類型與隱式返回
匿名函數(shù)也有類型猪瞬,匿名函數(shù)可以當(dāng)做變量賦值給函數(shù)類型變量,和其它變量一樣入篮,匿名函數(shù)就可以在代碼里傳遞了陈瘦。函數(shù)類型由傳入的參數(shù)和返回值類型決定。
匿名函數(shù)一般不需要return關(guān)鍵字來返回?cái)?shù)據(jù)潮售,那么為了返回?cái)?shù)據(jù)痊项,匿名函數(shù)會(huì)隱式返回函數(shù)體最后一行語句的結(jié)果。
//定義一個(gè)函數(shù)nowFun返回類型是String
val nowFun:()->String
nowFun = {
val name= "西塘河"
"你好 $name"
}
// 簡寫
val nowFun:()->String= {
val name= "西塘河"
"你好 $name"
}
println(nowFun()) // 打印 “你好 西塘河”
匿名函數(shù)參數(shù)
參數(shù)的類型放在匿名函數(shù)的類型定義中酥诽,參數(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("林憶蓮"))// 打印 “我喜歡:林憶蓮”
類型推斷
定義一個(gè)函數(shù)變量時(shí)咖驮,如果已經(jīng)把匿名函數(shù)賦值給了變量,就不用指定變量類型里了训枢。有參數(shù)時(shí)托修,匿名函數(shù)的參數(shù)名和類型都必須有
//省略前
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)
簡略傳函數(shù)參
如果一個(gè)函數(shù)的lambda參數(shù)排在最后或者是唯一的參數(shù)诀黍,那么括住lambda值的圓括號就可以省略掉了袋坑。
showTime(name = "容祖兒"){goodName:String,yarn:Int->
"$yarn 天貓雙十一 $goodName"
}
函數(shù)引用
上面講過了 把函數(shù)當(dāng)成參數(shù)傳給一個(gè)函數(shù)使用仗处,不光可以傳遞匿名函數(shù)也可以傳遞具名函數(shù)的引用眯勾,只要可以使用lambda表達(dá)式地方都可以使用函數(shù)引用。
fun setStudent(name:String,age:Int):String{
return "我是六年級的 $name 今年 $age 歲了"
}
fun setClass(name:String,student:(String,Int)->String){
println(student(name,12))
}
setClass("黃曉明", ::setStudent)//打印 “我是六年級的 黃曉明 今年 12 歲了”
函數(shù)類型作為返回類型
一個(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ù)又叫做高級函數(shù),高級函數(shù)廣泛用于函數(shù)式編程當(dāng)中文留。
lambda與匿名內(nèi)部類
為什么要在代碼中使用函數(shù)類型好唯?函數(shù)類型能讓開發(fā)者少寫模式化代碼,寫出更靈活的代碼燥翅。Java8支持lambda表達(dá)式骑篙,但不支持將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)或者變量,不過Java的替代方案是匿名函數(shù)森书。
- Kotlin使用匿名函數(shù)
kotlin使用匿名內(nè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)部類需要先創(chuàng)建一個(gè)接口
public static void main(String[] args) {
// 通過new一個(gè)匿名內(nèi)部類傳過去
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);
}