1药蜻、 componentX (多聲明)
val f1 = Forecast(Date(), 27.5f, "Shinny")
val (date, temperature, details) = f1
//=======================
// 上面的多聲明會被編譯成下面的代碼
val date = f1.component1()
val temperature = f1.component2()
val details = f1.copmponent3()
// 映射對象的每一個屬性到一個變量中结蟋,這就是 多聲明阁危。
// 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 暫時還不明真相,IDE 提示的。 操作符重載脯倒,函數(shù)名為操作符名(即系統(tǒng)默認(rèn)的關(guān)鍵詞实辑,此處為 component1,component2).當(dāng)使用該操作時,自己重寫的操作會覆蓋系統(tǒng)默認(rèn)的操作藻丢。
// 常見用法:該特性功能強(qiáng)大剪撬,可以極大的簡化代碼量。 如 map 中的擴(kuò)展函數(shù)實(shí)現(xiàn)悠反,允許在迭代時使用 key value
for ((key, value) in map) {
Log.d("map","key:$key, value:$value")
}
2残黑、 Companion objects (伴生對象)
類似于 java 中的 靜態(tài)屬性或方法,可以表示一個類中的靜態(tài)屬性斋否、常量梨水、函數(shù)。
3茵臭、with function
> 包含在 kotlin 的標(biāo)準(zhǔn)函數(shù)庫中疫诽。接收一個對象和一個擴(kuò)展函數(shù)作為它的參數(shù),然后使這個對象擴(kuò)展這個函數(shù)笼恰。表示所有在括號中編寫的代碼都是作為對象(第一個參數(shù))的一個擴(kuò)展函數(shù)踊沸,可以就像 this 一樣使用所有它的 public 方法和屬性。當(dāng)針對同一個對象做很多操作時非常有利于簡化代碼社证。
4逼龟、 operator 操作符重載
> Kotlin 有一些固定數(shù)量象征性的操作符,可以在任何類中很容易地使用追葡。方法是創(chuàng)建一個方法腺律,方法名為保留的操作符關(guān)鍵字,這樣就可以讓這個操作符的行為映射到這個方法宜肉。
一元操作符
操作符 | 函數(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ù)的形式被定義在箭頭的左邊(被圓括號包圍),然后在箭頭的右邊返回結(jié)果谬返。該例中之斯,接收一個 View, 返回 Unit
調(diào)用
view.setOnClickListener({ toast("clicked")})
// 當(dāng)定義了一個方法,必須使用大括號包圍遣铝,然后在箭頭的左邊指定參數(shù)佑刷,在箭頭的右邊返回函數(shù)執(zhí)行的結(jié)果。如果左邊的參數(shù)沒有使用到酿炸,可以省略左邊的參數(shù):
view.setOnClickListener({ toast("clicked")})
//如果這個函數(shù)的最后一個參數(shù)是一個函數(shù)瘫絮,可以把這個函數(shù)移動到圓括號外:
view.setOnClickListener() { toast("clicked")}
// 最后,如果這個函數(shù)只有一個參數(shù)填硕,可以省略這個圓括號
view.setOnClickListener { toast("clicked")}
4麦萤、 inline (內(nèi)聯(lián)函數(shù))
內(nèi)聯(lián)函數(shù)與普通的函數(shù)有點(diǎn)不同。一個內(nèi)聯(lián)函數(shù)會在編譯的時候被替換掉,而不是真正的方法調(diào)用壮莹。這在譯寫情況下可以減少內(nèi)存分配和運(yùn)行時開銷翅帜。例如,有一函數(shù)只接收一個函數(shù)作為它的參數(shù)垛孔。如果是普通函數(shù)藕甩,內(nèi)部會創(chuàng)建一個含有那個函數(shù)的對象。而內(nèi)聯(lián)函數(shù)會把我們調(diào)用這個函數(shù)的地方替換掉周荐,所以它不需要為此生成一個內(nèi)部的對象。
// 例一僵娃、創(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:一個包成員不能被定義為 protected.
3讯榕、internal:如果一個定義為 internal 的包成員的話,對所在的整個 module 可見匙睹。如果它是一個其他領(lǐng)域的成員愚屁,它就需要依賴那個領(lǐng)域的可見性。如有一個 private 類痕檬,那么它的 internal 修飾的函數(shù)的可見性會限制與它所在的該類的可見性霎槐。可以訪問同一個 module 中的 internal 修飾的類梦谜,但不能訪問其他 module的丘跌。
4、public: 僅受限于它的領(lǐng)域唁桩。一個定義為 public 的成員被包含在一個 privaet 修飾的勒種闭树,這個成員在這個類之外也是不可見的。
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.*
// 綁定一個 xml 中的 view 到另外一個 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
}
}
我們可能需要一個屬性具有一些相同的行為辩棒,使用 lazy 或 observable 可以被很有趣的實(shí)現(xiàn)重用,而不是一次又一次的去聲明那些相同的代碼。kotlin 提供了一個委托屬性到一個類的方法一睁。這就是委托屬性
class Delegate<T> : ReadWriteProperty<Any?, T> {
fun getValue(thisRef: Any?, property: KProperty<*>): T {
return ...
}
fun setValue(thisRef: Any?,property: KProperty<*>, value: T) {...}
// 如果該屬性是不可修改(val), 就會只有一個 getValue 函數(shù)
}
8.1钻弄、lazy
1、包含一個 lambda者吁,當(dāng)?shù)谝淮螆?zhí)行 getValue 時該 lambda 會被調(diào)用窘俺,所以該屬性可以被延遲初始化。之后的調(diào)用都只會返回同一個值复凳。
2瘤泪、lazy 操作符是線程安全的。
3育八、如果不擔(dān)心多線程問題或想提高更多的性能对途,可以使用 lazy(LazyThreadSafeMode.NONE) { ... }
4、一般 lazy 委托的代碼塊可以阻止在多個不同的線程中創(chuàng)建多個對象髓棋。
class App : Application() {
val database: SQLiteOpenHelper by lazy {
MyDatabaseHelper(applicationContext)
}
override fun onCreate() {
super.onCreate()
val db = database.writeableDatabase
}
}
8.2实檀、Observable
1、該委托可以檢測希望觀察的屬性變化按声。當(dāng)被觀察屬性的 set 方法被調(diào)用時膳犹,它就會自動執(zhí)行我們指定的 lambda 表達(dá)式。所以一旦該屬性被賦予了新值签则,則可以收到被委托的屬性须床、舊值和新值。
class ViewModel(val db: MyDatabase) {
var myProperty by Delegates.observable("") {
d,old,new ->
db.saveChanges(this,new)
}
}
8.3怀愧、Vetoable
1侨颈、一個特殊的 observable, 可以來決定是否保存這個值。在真正保存之前進(jìn)行一些條件判斷芯义。
var positiveNumber = Delegates.vetoable(0) {
d, old, new ->
new >= 0
}
// 上面這個委托只允許在新的值是正數(shù)時執(zhí)行保存哈垢。在 lambda 中,最后一行表示返回值扛拨。不需要使用 return 關(guān)鍵字(實(shí)質(zhì)上不能被編譯)
8.4耘分、Not Null
1、場景1:需要在某些地方初始化該屬性绑警,但不能在構(gòu)造函數(shù)中確定求泰,或不能在構(gòu)造函數(shù)中做任何事。
2计盒、場景2:在 Activity fragment service receivers...中渴频,一個非抽象的屬性在構(gòu)造函數(shù)執(zhí)行之前需要被賦值。
3北启、解決方案1:使用可 null 類型并且賦值為 null卜朗,直到真正去賦值拔第。氮素,在使用時就需要不停的進(jìn)行 not null 判斷场钉。
4蚊俺、解決方案2:使用 notnull 委托。含有一個可 null 的變量并會在設(shè)置該屬性時分配一個真實(shí)的值逛万。如果該值在被獲取之前沒有被分配泳猬,它就會拋出一個異常。
class App : Application() {
companion object {
var instance: App by Delegates.notnull()
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
8.5宇植、從 Map 中映射值
另一種委托方式得封,屬性的值會從一個map中獲取 value,屬性的名字對應(yīng)這個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 兩個類呛每,具體取決于被委托的對象是 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
}
}
// 此時可以在 app 的任何地方修改這個值,因?yàn)?*如果使用 Delegates.notNull(), 屬性必須是 var 的坡氯。可以使用剛剛創(chuàng)建的委托洋腮,只能修改該值一次
companion object {
var instance: App by DeleagesExt.notNullSingleValue()
}
9箫柳、集合和函數(shù)操作
1、Iterable: 父類啥供∶趸校可以遍歷一系列的都是實(shí)現(xiàn)這個接口
2、MutableIterable: 一個支持便利的同時可以執(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:如果至少有一個元素符合給出的判斷條件须蜗,則返回 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: 在一個初始值的基礎(chǔ)上從第一項(xiàng)到最后一項(xiàng)通過一個函數(shù)累計所有的元素
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 ,同時可得到元素的 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一樣,但沒有初始值护糖。通過一個函數(shù)從第一項(xiàng)到最后一項(xiàng)進(jìn)行累計褥芒。
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 個元素的所有元素的列表
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:過濾一個list 中指定 index 的元素
8忙干、take: 返回從第一個開始的 n 個元素
9、takeLast: 返回從最后一個開始的 n 個元素
10浪藻、takeWhile: 返回從第一個開始符合給定函數(shù)條件的元素
9.3捐迫、映射操作符
1、flatMap:遍歷所有的元素爱葵,為每一個創(chuàng)建一個集合施戴,最后把所有集合放在一個集合中反浓。
2、groupBy:返回一個根據(jù)給定函數(shù)分組后的 map
3赞哗、map:返回一個每一個元素根據(jù)給定函數(shù)轉(zhuǎn)換所組成的list
4雷则、mapIndexed:返回一個每一個元素根據(jù)給定的包含元素 index 的函數(shù)轉(zhuǎn)換所組成的 list
5、mapNotNull
9.4肪笋、元素操作符
1月劈、contains
2、elementAt:返回給定index對應(yīng)的元素藤乙,如果index數(shù)組越界則會拋出 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ù)的單個元素送丰,如果沒有符合或超過一個,則拋出異常
14弛秋、singleOrNull
9.5器躏、生產(chǎn)操作符
1、merge:把兩個集合合并為一個新的蟹略,相同index的元素通過給定的函數(shù)進(jìn)行合并生成新的元素作為新集合中的一個元素登失,返回新集合。新集合的大小由最小的那個集合大小決定
2挖炬、partition: 把一個給定集合的分割為兩個揽浙,第一個集合是由原集合每一項(xiàng)元素匹配給定函數(shù)條件返回 true 的元素組成,第二集合為false
3意敛、plus
4馅巷、zip:返回由 pair 組成的 list,每個 pair 由 兩個集合中相同index 的元素組成。該返回的 list 大小由最小的那個集合決定草姻。
5钓猬、unzip:從包含 pair 的 List 中生成包含List的Pair
9.6、順序操作符
1撩独、reverse:返回一個與指定list相反順序的list
2敞曹、sort:返回一個自然排序后的list
3账月、sortBy:指定函數(shù)排序
4、sortDescending:降序
5澳迫、sortDescendingBy:指定函數(shù)降序