Kotlin 基礎(chǔ)篇二

先來了解下集合初始化的方式

listOf創(chuàng)建的集合是一個(gè)<u>不可變的集合</u>,也就是不能調(diào)用添加或者刪除的方法。

//聲明一個(gè)list
val list= listOf("唐三","小舞","馬紅俊","戴沐白","朱竹清","奧斯卡","寧榮榮")

下面創(chuàng)建的集合是可變的。類似的set集合的創(chuàng)建方式是一樣的,set集合不允許重復(fù)元素。對(duì)應(yīng)的方式是setOf、mutableSetOf

val list= mutableListOf("唐三","小舞","馬紅俊","戴沐白","朱竹清","奧斯卡","寧榮榮");
list.add("白沉香")

map 的聲明和添加數(shù)據(jù)方式,以及遍歷數(shù)據(jù)。

val map=HashMap<String,Int>()
map["唐三"]=1;
map["小舞"]=2;
map["戴沐白"]=3;

for ((name,number) in map){
    println("name is $name,number is $number")
}

也可以這樣定義初始化map集合

//這個(gè)方式定義的map同樣是不能修改的 
val map = mapOf("唐三" to 1,"小舞" to 2,"戴沐白" to 3) 

跟list一樣,如果需要修改map的數(shù)據(jù),像這樣定義map,就可以添加或者刪除數(shù)據(jù)

val map= mutableMapOf("唐三" to 1,"小舞" to 2,"戴沐白" to 3)
map["朱竹清"]=4

下面來看Lambda的使用

<u>Lambda 就是一小段可以作為參數(shù)傳遞的代碼</u>,這一小段代碼不宜過長(zhǎng),否則會(huì)影響可讀性。

<u>Lambda語法結(jié)構(gòu){參數(shù)名1:參數(shù)類型,參數(shù)名2:參數(shù)類型->函數(shù)體}</u>,最后一行代碼會(huì)自動(dòng)作為L(zhǎng)ambda表達(dá)式的返回值。

//獲取長(zhǎng)度最長(zhǎng)的人名
 val list= mutableListOf("唐三" ,"小舞" ,"戴沐白" )
 val maxLength=list.maxByOrNull { name : String -> name.length }
 println("maxLength is $maxLength")

由于Kotlin出色的類型推到機(jī)制,Lambda表達(dá)式中參數(shù)的類型可以省略,上面的代碼可以簡(jiǎn)化

//由于出色的類型推到機(jī)制,上面的類型可以簡(jiǎn)化
val maxLength=list.maxByOrNull { name -> name.length }

當(dāng)Lambda表達(dá)式的參數(shù)列表只有一個(gè)的時(shí)候,也可以不必聲明參數(shù)名,而是可以使用it代替,進(jìn)一步簡(jiǎn)化

val maxLength=list.maxByOrNull { it.length }

上面的這種方式就是函數(shù)式API語法結(jié)構(gòu)

集合中的map函數(shù)是最常用的一種函數(shù)式API,它用于將集合中的每一個(gè)元素都映射成另外一個(gè)值,映射的規(guī)則在Lambda表達(dá)式中指定,最終生成一個(gè)新的集合

val list= listOf("tang san","xiao wu","dai mu bai","zhu zhu qing","ao si ka")
val newList=list.map { it.uppercase(Locale.CHINA) }
for (name in newList){
     println("name is $name")
 }

另外一個(gè)函數(shù)式API-filter,它是用來過濾集合中的數(shù)據(jù)的,它可以單獨(dú)使用也可以配合map一起使用。

val list= listOf("tang san","xiao wu","dai mu bai","zhu zhu qing","ao si ka")
val newList=list.filter { it.length>8 }.map { it.uppercase() }
for (name in newList){
    println("name is $name")
}

先使用filter進(jìn)行條件篩選,然后再轉(zhuǎn)成大寫,順序可以調(diào)換。

函數(shù)值A(chǔ)PI--any 和 all,any表示是否存在,all表示是否全部是,這兩個(gè)是條件判斷,返回true and false

//函數(shù)值A(chǔ)PI any all
val list= listOf("tang san","xiao wu","dai mu bai","zhu zhu qing","ao si ka")
val any = list.any { it.length > 8 }
val all = list.all { it.length > 8 }
println("any is $any , all is $all")  //any is true , all is false

java函數(shù)式API調(diào)用

如果在kotlin中調(diào)用一個(gè)java方法,并且該方法接收一個(gè)java單抽象方法接口參數(shù),就可以使用函數(shù)式API。

Thread { println("do some thing") }.start()

Thread 里邊需要一個(gè)參數(shù) Runnable ,Runnable里邊只有一個(gè)抽象run方法,所以可以直接省略這些。

val editText = EditText(context)
editText.addTextChangedListener(object : TextWatcher {
    override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
    override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
    override fun afterTextChanged(editable: Editable) {}
})

參數(shù)有多個(gè)抽象方法需要實(shí)現(xiàn),不能省略,書寫格式是這樣的。

空指針檢查

下面的函數(shù),當(dāng)調(diào)用的時(shí)候,是不能傳遞null參數(shù)的,直接會(huì)編譯不過去

fun readBooks(study: Study){
    study.readBooks()
}

Kotlin利用編譯判空檢查機(jī)制幾乎杜絕了空指針的異常,如果業(yè)務(wù)邏輯需要傳null的場(chǎng)景,可以定義可以為null的參數(shù)類型

  override fun onClick(v: View?) {
        when (v?.id) {
            R.id.iv_create_pci_finish -> picFinish()
        }
  }

這樣就可以傳null了,但是這樣寫依然編譯不過去,因?yàn)閭鬟f的參數(shù)可能會(huì)null就需要添加null判斷

Int? 可為null的整形 Int 不可為null的整形

String表示不可null的字符串 String?可為null的字符串

?.操作符

這個(gè)操作符表示不為null正常調(diào)用某個(gè)方法,當(dāng)對(duì)象為null則什么都不做。

?:操作符

這個(gè)操作符兩邊都接收一個(gè)表達(dá)式,如果左邊的表達(dá)式不為null就返回左邊的表達(dá)式,否則返回右邊的表達(dá)式

val c = a ?: b  
這個(gè)表達(dá)式相當(dāng)于
  val c = if (a != null) {
        a
    } else {
        b
    }

!!操作符

如果一個(gè)對(duì)象可能會(huì)null,這個(gè)時(shí)候這個(gè)對(duì)象調(diào)用某個(gè)方法編譯不會(huì)通過,如果不想添加判null操作,可以使用這個(gè)操作符!!,表示告訴kotlin,這個(gè)對(duì)象我非常確信不為null (感覺這個(gè)操作符沒啥用,直接加判null就好了)

//參數(shù)是一個(gè)可能會(huì)null的對(duì)象,這個(gè)時(shí)候如果不想添加判null需要編譯通過就需要使用!!這個(gè)操作符
 mVideoFragment!!.seekTimeline(
            timestamp,
            NvsStreamingContext.STREAMING_ENGINE_SEEK_FLAG_SHOW_ANIMATED_STICKER_POSTER
       )

let函數(shù),屬于kotlin的標(biāo)準(zhǔn)函數(shù)

let函數(shù)提供了函數(shù)式API的編程接口,并將原始調(diào)用對(duì)象作為參數(shù)傳遞到Lambda表達(dá)式中,let函數(shù)配合?.操作符非常好用

mTimelineEditor?.let {
    it.setSequencLeftPadding(sequenceLeftPadding)
    it.setSequencRightPadding(halfScreenWidth)
    it.setTimeSpanLeftPadding(sequenceLeftPadding)
}

字符串的內(nèi)嵌表達(dá)式

之前打印數(shù)據(jù)的時(shí)候已經(jīng)涉及到了,比如之前的打印表達(dá)式

"any is $any , all is $all"

函數(shù)的參數(shù)默認(rèn)值

fun test(num:Int,name:String="Tom"){
    println("num is $num, name is $name")
}

test(1) //這樣調(diào)用是合法的

這個(gè)函數(shù)第二個(gè)參數(shù)有一個(gè)默認(rèn)值,那么調(diào)用這個(gè)函數(shù)的時(shí)候,可以只傳遞第一個(gè)參數(shù),也可以兩個(gè)都傳遞

fun test(name:String="Tom",num:Int){
    println("num is $num, name is $name")
}

test(num=1) //通過鍵值對(duì)的方式傳遞參數(shù)就可以調(diào)用了

如果第一個(gè)參數(shù)是帶默認(rèn)值,直接像test(1)就會(huì)報(bào)錯(cuò),kotlin認(rèn)為配型不匹配。這個(gè)問題可以使用鍵值對(duì)的方式進(jìn)行傳值,這個(gè)也是允許的

Kotlin 另外幾個(gè)常用的標(biāo)準(zhǔn)函數(shù)

with、run、aplly這幾個(gè)標(biāo)準(zhǔn)函數(shù)在開發(fā)中會(huì)經(jīng)常使用到,kotlin中的標(biāo)準(zhǔn)函數(shù)是指在Standard.kt文件中定義的函數(shù),任何Kotlin的代碼都可以隨便調(diào)用使用。

with函數(shù)接收兩個(gè)參數(shù),第一個(gè)參數(shù)是任意類型的對(duì)象,第二個(gè)參數(shù)是一個(gè)Lambda表達(dá)式,with函數(shù)會(huì)在Lambda表達(dá)式中提供第一個(gè)參數(shù)的對(duì)象的上下文,并使用Lambda表達(dá)式最后一行的表達(dá)式作為返回值。

NvsStreamingContext.SdkVersion sdkVersion = mStreamingContext.getSdkVersion();
StringBuilder stringBuilder = new StringBuilder("V ");
stringBuilder.append(sdkVersion.majorVersion);
stringBuilder.append(".");
stringBuilder.append(sdkVersion.minorVersion);
stringBuilder.append(".");
stringBuilder.append(sdkVersion.revisionNumber);
mSDKVersion.setText(stringBuilder.toString());

上面是sdk demo中的代碼,如果使用with函數(shù)進(jìn)行改造

NvsStreamingContext.SdkVersion sdkVersion = mStreamingContext.getSdkVersion();
val result=with(StringBuilder()){
    append("V ")
    append(sdkVersion.majorVersion)
    append(".")
    append(sdkVersion.minorVersion)
    append(".")
    append(sdkVersion.revisionNumber)
    toString()
}
mSDKVersion.setText(result);

使用with函數(shù)代碼變的更加精簡(jiǎn)

run函數(shù)

這個(gè)函數(shù)跟with函數(shù)類似,得到的結(jié)果也相似。

val result=StringBuilder().run{
    append("V ")
    append(sdkVersion.majorVersion)
    append(".")
    append(sdkVersion.minorVersion)
    append(".")
    append(sdkVersion.revisionNumber)
    toString()
}
mSDKVersion.setText(result);

aplly函數(shù)

這個(gè)函數(shù)跟run函數(shù)類型,但是最后一行不是返回值,而是返回對(duì)象本身,下面是一個(gè)實(shí)際應(yīng)用的例子。

 mStartNextActivity.setOnClickListener {
            val intent=Intent(this,OtherActivity::class.java).apply {
                putExtra("param1",1)
                putExtra("param2","2")
                putExtra("param1",1)
            }
            startActivity(intent)
        }

kotlin中定義靜態(tài)方法

相比于java,kotlin中因?yàn)閱卫芎?jiǎn)單,弱化靜態(tài)方法的概念。像java中的工具類Kotlin中推薦直接使用單例進(jìn)行實(shí)現(xiàn)。

object Utils {

    private const val MIN_DELAY_TIME = 1000
    private var lastClickTime: Long = 0

    /**
     *兩次點(diǎn)擊間隔不能少于1000ms
     * The interval between two clicks cannot be less than 1000ms
     */
    fun isFastClick(): Boolean {
        var flag = true
        val currentClickTime = System.currentTimeMillis()
        if (currentClickTime - lastClickTime >= MIN_DELAY_TIME) {
            flag = false
        }
        lastClickTime = currentClickTime
        return flag
    }
}

這樣處理之后,里邊所有的方法就可以像靜態(tài)方法那樣調(diào)用了。

如果某個(gè)類里邊,有對(duì)象方法也想要靜態(tài)方法怎么辦?可以使用companion object

class Utils {

    companion object{
        private val MIN_DELAY_TIME = 1000
        private var lastClickTime: Long = 0
        /**
         *兩次點(diǎn)擊間隔不能少于1000ms
         * The interval between two clicks cannot be less than 1000ms
         */
        fun isFastClick(): Boolean {
            var flag = true
            val currentClickTime = System.currentTimeMillis()
            if (currentClickTime - lastClickTime >= MIN_DELAY_TIME) {
                flag = false
            }
            lastClickTime = currentClickTime
            return flag
        }

    }
   
    
    fun doAction(){
        Log.e("Utils","doAction")
    }
}

像上面這樣編寫就能解決上面的問題,isFastClick這個(gè)方法仍然可以像靜態(tài)方法那樣調(diào)用,doaction就是一個(gè)對(duì)象方法。但是這樣處理在原理上isFastClick并不是一個(gè)靜態(tài)方法,companion object這個(gè)關(guān)鍵字會(huì)在Utils類中創(chuàng)建伴生類,kotlin保證只會(huì)存在一個(gè)伴生類。

如果想要定義真正意義的靜態(tài)方法,kotlin提供了兩個(gè)方式:注解和頂層方法。

companion object只是在語法上模擬了靜態(tài)方法的調(diào)用方式,如果加上@JvmStatic注解,那么kotlin編譯器會(huì)將這個(gè)方法編譯成真正的靜態(tài)方法。

class Utils {

    companion object{
        private val MIN_DELAY_TIME = 1000
        private var lastClickTime: Long = 0
        /**
         *兩次點(diǎn)擊間隔不能少于1000ms
         * The interval between two clicks cannot be less than 1000ms
         */
        @JvmStatic
        fun isFastClick(): Boolean {
            var flag = true
            val currentClickTime = System.currentTimeMillis()
            if (currentClickTime - lastClickTime >= MIN_DELAY_TIME) {
                flag = false
            }
            lastClickTime = currentClickTime
            return flag
        }

    }


    fun doAction(){
        Log.e("Utils","doAction")
    }
}

這樣isFastClick就是真正意義上的靜態(tài)方法了。@JvmStatic 這個(gè)注解不能加在普通方法中會(huì)報(bào)錯(cuò)。

kotlin頂層方法

頂層方法是指,沒有定義在任何類中的方法。在kotlin中創(chuàng)建Kotlin file ,在file中定義的方法都是靜態(tài)方法,全局可以調(diào)用也是真正意義的靜態(tài)方法,全局可以調(diào)用。

延遲初始化

private var mTimeline: NvsTimeline? = null

這是聲明全局變量的方式,如果這樣初始化,那么在使用mTimeline這個(gè)對(duì)象的時(shí)候需要頻繁的使用?.進(jìn)行判空操作,否則編譯不過去,由于kotlin編譯機(jī)制就不得不編寫大量額外的判空操作。

如何解決這個(gè)問題呢?延時(shí)初始化lateinit使用這個(gè)關(guān)鍵字修飾全局變量,這樣聲明的變量不為null,使用的時(shí)候可以避免頻繁的判空操作。

private lateinit var mTimeline: NvsTimeline

但是這個(gè)關(guān)鍵字本身是有風(fēng)險(xiǎn)的,如果使用之前沒有初始化會(huì)拋異常,所以當(dāng)對(duì)一個(gè)全局的變量使用了lateinit關(guān)鍵字,請(qǐng)確保它在被任何地方調(diào)用之前已經(jīng)初始化。

在使用全局變量之前可以通過代碼來判斷全部變量是否已經(jīng)初始化,::mTimeline.isInitialized這個(gè)就是判斷對(duì)象是否會(huì)null的方法。

if(!::mTimeline.isInitialized){
    mTimeline=initTimeline()
}

擴(kuò)展函數(shù)

擴(kuò)展函數(shù)表示在不修改某個(gè)類源碼的基礎(chǔ)上,仍然可以打開這個(gè)類,向該類添加新方法。

擴(kuò)展函數(shù)的語法結(jié)構(gòu)

fun ClassName.methodName(param1:Int,Param2:Int):Int{
    return 0;
}

擴(kuò)展函數(shù)可以放在頂層函數(shù),這樣擴(kuò)展函數(shù)就擁有了全局的訪問域。

fun String.lowersCount():Int{
    var count=0
    for (low in this){
        if (low.isLowerCase()){
            count++
        }
    }
    return count
}
   //測(cè)試方法
  val lowNum="asdWERff".lowersCount()
  println("lowNum is $lowNum ")
   //輸出日志
  //lowNum is 5   

上面是給String定義的一個(gè)統(tǒng)計(jì)小寫字母?jìng)€(gè)數(shù)的方法,這個(gè)在String類里邊是沒有的。利用這個(gè)特性,可以寫出豐富多樣的擴(kuò)展函數(shù),非常好用。擴(kuò)展函數(shù)在kotlin中沒有任何限制,可以再任何類上添加擴(kuò)展函數(shù),這將大大提升代碼質(zhì)量和研發(fā)效率。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容