kotlin 常見 關(guān)鍵詞

1、 componentX (多聲明)

val f1 = Forecast(Date(), 27.5f, "Shinny")
val (date, temperature, details) = f1
//=======================
// 上面的多聲明會(huì)被編譯成下面的代碼
val date = f1.component1()
val temperature = f1.component2()
val details = f1.copmponent3()
// 映射對(duì)象的每一個(gè)屬性到一個(gè)變量中,這就是 多聲明。
// object class 默認(rèn)具有該屬性。但普通 class 想要具有這種屬性,需要這樣做:
class person(val name: String, val age: Int) {
    operator fun component1(): String {
        return name
    }
    operator fun component2(): Int {
        return age
    }
}

val 必須有: 用來保存在 component1 和 component2 中返回構(gòu)造函數(shù)傳進(jìn)來的參數(shù)的。
operator 暫時(shí)還不明真相,IDE 提示的。 操作符重載,函數(shù)名為操作符名(即系統(tǒng)默認(rèn)的關(guān)鍵詞,此處為 component1,component2).當(dāng)使用該操作時(shí),自己重寫的操作會(huì)覆蓋系統(tǒng)默認(rèn)的操作。

// 常見用法:該特性功能強(qiáng)大,可以極大的簡(jiǎn)化代碼量。 如 map 中的擴(kuò)展函數(shù)實(shí)現(xiàn),允許在迭代時(shí)使用 key value
for ((key, value) in map) {
    Log.d("map","key:$key, value:$value")
}

2、 Companion objects (伴生對(duì)象)

類似于 java 中的 靜態(tài)屬性或方法,可以表示一個(gè)類中的靜態(tài)屬性、常量、函數(shù)。

3、with function

 > 包含在 kotlin 的標(biāo)準(zhǔn)函數(shù)庫中。接收一個(gè)對(duì)象和一個(gè)擴(kuò)展函數(shù)作為它的參數(shù),然后使這個(gè)對(duì)象擴(kuò)展這個(gè)函數(shù)。表示所有在括號(hào)中編寫的代碼都是作為對(duì)象(第一個(gè)參數(shù))的一個(gè)擴(kuò)展函數(shù),可以就像 this 一樣使用所有它的 public 方法和屬性。當(dāng)針對(duì)同一個(gè)對(duì)象做很多操作時(shí)非常有利于簡(jiǎn)化代碼。

4、 operator 操作符重載

  > Kotlin 有一些固定數(shù)量象征性的操作符,可以在任何類中很容易地使用。方法是創(chuàng)建一個(gè)方法,方法名為保留的操作符關(guān)鍵字,這樣就可以讓這個(gè)操作符的行為映射到這個(gè)方法。
一元操作符
操作符 函數(shù)
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a++ a.inc()
a-- a.dec()
二元操作符
操作符 函數(shù)
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.mod(b)
a..b a.rangeTo(b)
a in b a.contains(b)
a !In b !a.contains(b)
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.modAssign(b)
數(shù)組操作符
操作符 函數(shù)
a[i] a.get(i)
a[i,j] a.get(i,j)
a[i_1,...,i_n] a.get(i_1,...,i_n)
a[i] = b a.set(i,b)
a[i,j] = b a.set(i,j,b)
a[i_1,...,i_n] = b a.set(i_1,...,i_n,b)
等于操作符
操作符 函數(shù)
a == b a?.equals(b)?:b === null
a != b !(a?.equals(b)?: b === null)
函數(shù)調(diào)用操作符
操作符 函數(shù)
a(i) a.invoke(i)
a(i,j) a.invoke(i,j)
a(i_1,...,i_n) a.invoke(i_1,...,i_n)

3、 lambda

函數(shù)里定義 lambda 表達(dá)式形參

 fun setOnClickListener(listener: (View) -> Unit)
 // 表達(dá)式通過參數(shù)的形式被定義在箭頭的左邊(被圓括號(hào)包圍),然后在箭頭的右邊返回結(jié)果。該例中,接收一個(gè) View, 返回 Unit

調(diào)用

view.setOnClickListener({ toast("clicked")})
// 當(dāng)定義了一個(gè)方法,必須使用大括號(hào)包圍,然后在箭頭的左邊指定參數(shù),在箭頭的右邊返回函數(shù)執(zhí)行的結(jié)果。如果左邊的參數(shù)沒有使用到,可以省略左邊的參數(shù):
view.setOnClickListener({ toast("clicked")})
//如果這個(gè)函數(shù)的最后一個(gè)參數(shù)是一個(gè)函數(shù),可以把這個(gè)函數(shù)移動(dòng)到圓括號(hào)外:
view.setOnClickListener() { toast("clicked")}
// 最后,如果這個(gè)函數(shù)只有一個(gè)參數(shù),可以省略這個(gè)圓括號(hào)
view.setOnClickListener { toast("clicked")}

4、 inline (內(nèi)聯(lián)函數(shù))

內(nèi)聯(lián)函數(shù)與普通的函數(shù)有點(diǎn)不同。一個(gè)內(nèi)聯(lián)函數(shù)會(huì)在編譯的時(shí)候被替換掉,而不是真正的方法調(diào)用。這在譯寫情況下可以減少內(nèi)存分配和運(yùn)行時(shí)開銷。例如,有一函數(shù)只接收一個(gè)函數(shù)作為它的參數(shù)。如果是普通函數(shù),內(nèi)部會(huì)創(chuàng)建一個(gè)含有那個(gè)函數(shù)的對(duì)象。而內(nèi)聯(lián)函數(shù)會(huì)把我們調(diào)用這個(gè)函數(shù)的地方替換掉,所以它不需要為此生成一個(gè)內(nèi)部的對(duì)象。

 // 例一、創(chuàng)建代碼塊只提供 Lollipop 或更高版本來執(zhí)行
inline fun supportsLollipop(code: () -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        code()
    }
}
// usage
supportsLollipop {
    window.setStatusBarColor(Color.BLACK)
}

5、可見性修飾符

  1、private
  2、protected:一個(gè)包成員不能被定義為 protected.
  3、internal:如果一個(gè)定義為  internal 的包成員的話,對(duì)所在的整個(gè) module 可見。如果它是一個(gè)其他領(lǐng)域的成員,它就需要依賴那個(gè)領(lǐng)域的可見性。如有一個(gè) private 類,那么它的 internal 修飾的函數(shù)的可見性會(huì)限制與它所在的該類的可見性??梢栽L問同一個(gè) module 中的 internal 修飾的類,但不能訪問其他 module的。
  4、public: 僅受限于它的領(lǐng)域。一個(gè)定義為 public 的成員被包含在一個(gè) privaet 修飾的勒種,這個(gè)成員在這個(gè)類之外也是不可見的。

6、構(gòu)造器

  所有構(gòu)造器默認(rèn)都是 public 的,它們類是可見的,可以被其他地方使用。也可以使用該語法把構(gòu)造函數(shù)修改為 private:
  class C private constructor(a: Int) {...}

7、Kotlin for Android Extensions

7.1、Activities / Fragments 的 Android Extensions
  import kotlinx.android.synthetic.activity_main.*
  // 在 setContentView 被調(diào)用后就可以通過 id 名來訪問 XML 中定義的 View
  import kotlinx.android.synthetic.activity_main.*
  // 可以通過 include 標(biāo)簽在 activity 默認(rèn)布局中增加內(nèi)嵌的布局。
7.2、Views Android Extensions
  import kotlinx.android.synthetic.view_item.view.*
  // 綁定一個(gè) xml 中的 view 到另外一個(gè) view。

8、Application 單例化和屬性的 Delegated (by)

  class App : Application() {
      companion object {
          private var instance: Application? = null
          fun  instance() = instance!!
      }
      override fun onCreate() {
          super.onCreate()
          instance = this
      }
  }

我們可能需要一個(gè)屬性具有一些相同的行為,使用 lazy 或 observable 可以被很有趣的實(shí)現(xiàn)重用,而不是一次又一次的去聲明那些相同的代碼。kotlin 提供了一個(gè)委托屬性到一個(gè)類的方法。這就是委托屬性

 class Delegate<T> : ReadWriteProperty<Any?, T> {
      fun getValue(thisRef: Any?, property: KProperty<*>): T {
            return ...
      }
      fun setValue(thisRef: Any?,property: KProperty<*>, value: T) {...}  
      // 如果該屬性是不可修改(val), 就會(huì)只有一個(gè) getValue 函數(shù)
  }
8.1、lazy
  1、包含一個(gè) lambda,當(dāng)?shù)谝淮螆?zhí)行 getValue 時(shí)該 lambda 會(huì)被調(diào)用,所以該屬性可以被延遲初始化。之后的調(diào)用都只會(huì)返回同一個(gè)值。
  2、lazy 操作符是線程安全的。  
  3、如果不擔(dān)心多線程問題或想提高更多的性能,可以使用 lazy(LazyThreadSafeMode.NONE) { ... }
  4、一般 lazy 委托的代碼塊可以阻止在多個(gè)不同的線程中創(chuàng)建多個(gè)對(duì)象。
class App : Application() {
   val database: SQLiteOpenHelper by lazy {
       MyDatabaseHelper(applicationContext)
    }
    override fun onCreate() {
      super.onCreate()
      val db = database.writeableDatabase
    }
}
8.2、Observable
  1、該委托可以檢測(cè)希望觀察的屬性變化。當(dāng)被觀察屬性的 set 方法被調(diào)用時(shí),它就會(huì)自動(dòng)執(zhí)行我們指定的 lambda 表達(dá)式。所以一旦該屬性被賦予了新值,則可以收到被委托的屬性、舊值和新值。
class ViewModel(val db: MyDatabase) {
  var myProperty by Delegates.observable("") {
    d,old,new ->
    db.saveChanges(this,new)
  }
}
8.3、Vetoable
1、一個(gè)特殊的 observable, 可以來決定是否保存這個(gè)值。在真正保存之前進(jìn)行一些條件判斷。
var positiveNumber = Delegates.vetoable(0) {
    d, old, new -> 
    new >= 0
}
// 上面這個(gè)委托只允許在新的值是正數(shù)時(shí)執(zhí)行保存。在 lambda 中,最后一行表示返回值。不需要使用 return 關(guān)鍵字(實(shí)質(zhì)上不能被編譯)
8.4、Not Null
  1、場(chǎng)景1:需要在某些地方初始化該屬性,但不能在構(gòu)造函數(shù)中確定,或不能在構(gòu)造函數(shù)中做任何事。
  2、場(chǎng)景2:在 Activity fragment service receivers...中,一個(gè)非抽象的屬性在構(gòu)造函數(shù)執(zhí)行之前需要被賦值。
   3、解決方案1:使用可 null 類型并且賦值為 null,直到真正去賦值。氮素,在使用時(shí)就需要不停的進(jìn)行 not null 判斷。
   4、解決方案2:使用 notnull 委托。含有一個(gè)可 null 的變量并會(huì)在設(shè)置該屬性時(shí)分配一個(gè)真實(shí)的值。如果該值在被獲取之前沒有被分配,它就會(huì)拋出一個(gè)異常。
class App : Application() {
  companion object {
    var instance: App by Delegates.notnull()
  }
   override fun onCreate() {
      super.onCreate()
      instance = this
    }
}
8.5、從 Map 中映射值
  另一種委托方式,屬性的值會(huì)從一個(gè)map中獲取 value,屬性的名字對(duì)應(yīng)這個(gè)map 中的 key。
import kotlin.properties.getValue
class Configuration(map: Map<String,Any?>) {
  val width: Int by map
  val height: Int by map
  val dp: Int by map
  val deviceName: String by map
}
// usage
conf = Configuration(mapof(
  "width" to 1080,
  "height" to 720,
  "dp" to 240,
   "deviceName" to "myDecive"
))
8.6 custom delegate
 自定義委托需要實(shí)現(xiàn) ReadOonlyProperty / ReadWriteProperty 兩個(gè)類,具體取決于被委托的對(duì)象是 val 還是 var
// step1
private class NotNullSingleValueVar<T>() : ReadWriteProperty<Any?, T> {
  private var value: T? = null
  override fun getValue(thisRef: Any?, property: KProperty<*>): T {
      return value ?: throw IllegalStateException("${desc.name not initialized}")
  }
  
  override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
      this.value = if (this.value == null) value else throw IllegalStateException("${desc.name} already initialized")
      }
}
// step2: usage
object DelegatesExt {
  fun notNullSingleValue<T>(): ReadWriteProperty<Any?, T> = NotNullSingleValueVar()
}
8.7 重新實(shí)現(xiàn) Application 單例
class App : Application() {
    companion object {
        var instance: App by Delegates.notNull()
    }

    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}  
// 此時(shí)可以在 app 的任何地方修改這個(gè)值,因?yàn)?*如果使用 Delegates.notNull(), 屬性必須是 var 的??梢允褂脛倓倓?chuàng)建的委托,只能修改該值一次
companion object {
    var instance: App by DeleagesExt.notNullSingleValue()
}

9、集合和函數(shù)操作

  1、Iterable: 父類??梢员闅v一系列的都是實(shí)現(xiàn)這個(gè)接口
  2、MutableIterable: 一個(gè)支持便利的同時(shí)可以執(zhí)行刪除的 Iterables
  3、Collection:
  4、MutableCollection:支持增加刪除item 的 collection。提供了額外的函數(shù),如 add、remove、clear等
  5、List: 范性有序集合。
  6、MutableList: 支持增刪item 的 List
  7、Set: 無序并不支持重復(fù) item 的 集合
  8、MutableSet: 支持增刪item 的 Set
  9、 Map: 
  10、MutableMap: 支持增刪 item 的 map
9.1、總數(shù)操作符

1、Any:如果至少有一個(gè)元素符合給出的判斷條件,則返回 true

val list = listOf(1,2,3,4,5,6)
assertTrue(list.any { it % 2 == 0 })
assertFalse(list.any { it > 10})

2、all:如果全部的元素符合給出的判斷條件,則返回 true

assertTrue(list.add { it < 10})
assertFalse(list.all { it % 2 == 0})

3、count: 返回符合給出判斷條件的元素總數(shù)

assertEquals(3,list.count {it % 2 == 0})

4、fold: 在一個(gè)初始值的基礎(chǔ)上從第一項(xiàng)到最后一項(xiàng)通過一個(gè)函數(shù)累計(jì)所有的元素

asserEquals(25, list.fold(4) { total, next -> total + next})

5、foldRight: 與 fold 一樣,但順序是從最后一項(xiàng)到第一項(xiàng)。
6、forEach: 遍歷所有元素,并執(zhí)行給定的操作。

list.forEach { println(it) }

7、forEachIndexed: 與 forEach ,同時(shí)可得到元素的 Index

list.forEachIndexed { index, value -> println("position $index contains a $value")}

8、max: 返回最大一項(xiàng),如果沒有則返回 null
9、maxBy: 根據(jù)給定的函數(shù)返回最大的一項(xiàng),沒有返回 null

assertEquals(1, list.maxBy { -it })

10、min
11、minBy
12、none
13、reduce:與fold一樣,但沒有初始值。通過一個(gè)函數(shù)從第一項(xiàng)到最后一項(xiàng)進(jìn)行累計(jì)。

assertEquals(21, list.reduce {total, next -> total + next})

14、reduceRight: 順序從最后一項(xiàng)到第一項(xiàng)
15、sumBy: 返回所有每一項(xiàng)通過函數(shù)轉(zhuǎn)換之后的數(shù)據(jù)的總和。

9.2、過濾操作符

1、drop:返回包含去掉前 n 個(gè)元素的所有元素的列表

assertEquals(listOf(5,6), list.drop(4))

2、dropWhile: 返回根據(jù)給定函數(shù)從第一項(xiàng)開始去掉指定元素的列表
3、dropLastWhile:返回根據(jù)給定函數(shù)從最后一項(xiàng)開始去掉指定元素的列表
4、filter:過濾

assertEquals(listOf(2,4,6), list.filter{it % 2 == 0})

5、filterNot
6、filterNotNull
7、slice:過濾一個(gè)list 中指定 index 的元素
8、take: 返回從第一個(gè)開始的 n 個(gè)元素
9、takeLast: 返回從最后一個(gè)開始的 n 個(gè)元素
10、takeWhile: 返回從第一個(gè)開始符合給定函數(shù)條件的元素

9.3、映射操作符

1、flatMap:遍歷所有的元素,為每一個(gè)創(chuàng)建一個(gè)集合,最后把所有集合放在一個(gè)集合中。
2、groupBy:返回一個(gè)根據(jù)給定函數(shù)分組后的 map
3、map:返回一個(gè)每一個(gè)元素根據(jù)給定函數(shù)轉(zhuǎn)換所組成的list
4、mapIndexed:返回一個(gè)每一個(gè)元素根據(jù)給定的包含元素 index 的函數(shù)轉(zhuǎn)換所組成的 list
5、mapNotNull

9.4、元素操作符

1、contains
2、elementAt:返回給定index對(duì)應(yīng)的元素,如果index數(shù)組越界則會(huì)拋出 IndexOutOfBoundsException
3、elementAtOrElse: 越界則給出默認(rèn)值
4、elementAtOrNull
5、first
6、firstOrNull
7、indexOf
8、indexofFirst
9、indexOfLast
10、last
11、lastIndexOf
12、lastOrNull
13、single:返回符合給定函數(shù)的單個(gè)元素,如果沒有符合或超過一個(gè),則拋出異常
14、singleOrNull

9.5、生產(chǎn)操作符

1、merge:把兩個(gè)集合合并為一個(gè)新的,相同index的元素通過給定的函數(shù)進(jìn)行合并生成新的元素作為新集合中的一個(gè)元素,返回新集合。新集合的大小由最小的那個(gè)集合大小決定
2、partition: 把一個(gè)給定集合的分割為兩個(gè),第一個(gè)集合是由原集合每一項(xiàng)元素匹配給定函數(shù)條件返回 true 的元素組成,第二集合為false
3、plus
4、zip:返回由 pair 組成的 list,每個(gè) pair 由 兩個(gè)集合中相同index 的元素組成。該返回的 list 大小由最小的那個(gè)集合決定。
5、unzip:從包含 pair 的 List 中生成包含List的Pair

9.6、順序操作符

1、reverse:返回一個(gè)與指定list相反順序的list
2、sort:返回一個(gè)自然排序后的list
3、sortBy:指定函數(shù)排序
4、sortDescending:降序
5、sortDescendingBy:指定函數(shù)降序

最后編輯于
?著作權(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)容