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 默认具有该属性。但普通 class 想要具有这种属性,需要这样做:
class person(val name: String, val age: Int) {
operator fun component1(): String {
return name
}
operator fun component2(): Int {
return age
}
}
val 必须有: 用来保存在 component1 和 component2 中返回构造函数传进来的参数的。
operator 暂时还不明真相,IDE 提示的。 操作符重载,函数名为操作符名(即系统默认的关键词,此处为 component1,component2).当使用该操作时,自己重写的操作会覆盖系统默认的操作。
// 常见用法:该特性功能强大,可以极大的简化代码量。 如 map 中的扩展函数实现,允许在迭代时使用 key value
for ((key, value) in map) {
Log.d("map","key:$key, value:$value")
}
2、 Companion objects (伴生对象)
类似于 java 中的 静态属性或方法,可以表示一个类中的静态属性、常量、函数。
3、with function
> 包含在 kotlin 的标准函数库中。接收一个对象和一个扩展函数作为它的参数,然后使这个对象扩展这个函数。表示所有在括号中编写的代码都是作为对象(第一个参数)的一个扩展函数,可以就像 this 一样使用所有它的 public 方法和属性。当针对同一个对象做很多操作时非常有利于简化代码。
4、 operator 操作符重载
> Kotlin 有一些固定数量象征性的操作符,可以在任何类中很容易地使用。方法是创建一个方法,方法名为保留的操作符关键字,这样就可以让这个操作符的行为映射到这个方法。
一元操作符
操作符 | 函数 |
---|---|
+a | a.unaryPlus() |
-a | a.unaryMinus() |
!a | a.not() |
a++ | a.inc() |
a-- | a.dec() |
二元操作符
操作符 | 函数 |
---|---|
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) |
数组操作符
操作符 | 函数 |
---|---|
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) |
等于操作符
操作符 | 函数 |
---|---|
a == b | a?.equals(b)?:b === null |
a != b | !(a?.equals(b)?: b === null) |
函数调用操作符
操作符 | 函数 |
---|---|
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
函数里定义 lambda 表达式形参
fun setOnClickListener(listener: (View) -> Unit)
// 表达式通过参数的形式被定义在箭头的左边(被圆括号包围),然后在箭头的右边返回结果。该例中,接收一个 View, 返回 Unit
调用
view.setOnClickListener({ toast("clicked")})
// 当定义了一个方法,必须使用大括号包围,然后在箭头的左边指定参数,在箭头的右边返回函数执行的结果。如果左边的参数没有使用到,可以省略左边的参数:
view.setOnClickListener({ toast("clicked")})
//如果这个函数的最后一个参数是一个函数,可以把这个函数移动到圆括号外:
view.setOnClickListener() { toast("clicked")}
// 最后,如果这个函数只有一个参数,可以省略这个圆括号
view.setOnClickListener { toast("clicked")}
4、 inline (内联函数)
内联函数与普通的函数有点不同。一个内联函数会在编译的时候被替换掉,而不是真正的方法调用。这在译写情况下可以减少内存分配和运行时开销。例如,有一函数只接收一个函数作为它的参数。如果是普通函数,内部会创建一个含有那个函数的对象。而内联函数会把我们调用这个函数的地方替换掉,所以它不需要为此生成一个内部的对象。
// 例一、创建代码块只提供 Lollipop 或更高版本来执行
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 可见。如果它是一个其他领域的成员,它就需要依赖那个领域的可见性。如有一个 private 类,那么它的 internal 修饰的函数的可见性会限制与它所在的该类的可见性。可以访问同一个 module 中的 internal 修饰的类,但不能访问其他 module的。
4、public: 仅受限于它的领域。一个定义为 public 的成员被包含在一个 privaet 修饰的勒种,这个成员在这个类之外也是不可见的。
6、构造器
所有构造器默认都是 public 的,它们类是可见的,可以被其他地方使用。也可以使用该语法把构造函数修改为 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 被调用后就可以通过 id 名来访问 XML 中定义的 View
import kotlinx.android.synthetic.activity_main.*
// 可以通过 include 标签在 activity 默认布局中增加内嵌的布局。
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 可以被很有趣的实现重用,而不是一次又一次的去声明那些相同的代码。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 函数
}
8.1、lazy
1、包含一个 lambda,当第一次执行 getValue 时该 lambda 会被调用,所以该属性可以被延迟初始化。之后的调用都只会返回同一个值。
2、lazy 操作符是线程安全的。
3、如果不担心多线程问题或想提高更多的性能,可以使用 lazy(LazyThreadSafeMode.NONE) { ... }
4、一般 lazy 委托的代码块可以阻止在多个不同的线程中创建多个对象。
class App : Application() {
val database: SQLiteOpenHelper by lazy {
MyDatabaseHelper(applicationContext)
}
override fun onCreate() {
super.onCreate()
val db = database.writeableDatabase
}
}
8.2、Observable
1、该委托可以检测希望观察的属性变化。当被观察属性的 set 方法被调用时,它就会自动执行我们指定的 lambda 表达式。所以一旦该属性被赋予了新值,则可以收到被委托的属性、旧值和新值。
class ViewModel(val db: MyDatabase) {
var myProperty by Delegates.observable("") {
d,old,new ->
db.saveChanges(this,new)
}
}
8.3、Vetoable
1、一个特殊的 observable, 可以来决定是否保存这个值。在真正保存之前进行一些条件判断。
var positiveNumber = Delegates.vetoable(0) {
d, old, new ->
new >= 0
}
// 上面这个委托只允许在新的值是正数时执行保存。在 lambda 中,最后一行表示返回值。不需要使用 return 关键字(实质上不能被编译)
8.4、Not Null
1、场景1:需要在某些地方初始化该属性,但不能在构造函数中确定,或不能在构造函数中做任何事。
2、场景2:在 Activity fragment service receivers...中,一个非抽象的属性在构造函数执行之前需要被赋值。
3、解决方案1:使用可 null 类型并且赋值为 null,直到真正去赋值。氮素,在使用时就需要不停的进行 not null 判断。
4、解决方案2:使用 notnull 委托。含有一个可 null 的变量并会在设置该属性时分配一个真实的值。如果该值在被获取之前没有被分配,它就会抛出一个异常。
class App : Application() {
companion object {
var instance: App by Delegates.notnull()
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
8.5、从 Map 中映射值
另一种委托方式,属性的值会从一个map中获取 value,属性的名字对应这个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
自定义委托需要实现 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 重新实现 Application 单例
class App : Application() {
companion object {
var instance: App by Delegates.notNull()
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
// 此时可以在 app 的任何地方修改这个值,因为**如果使用 Delegates.notNull(), 属性必须是 var 的。可以使用刚刚创建的委托,只能修改该值一次
companion object {
var instance: App by DeleagesExt.notNullSingleValue()
}
9、集合和函数操作
1、Iterable: 父类。可以遍历一系列的都是实现这个接口
2、MutableIterable: 一个支持便利的同时可以执行删除的 Iterables
3、Collection:
4、MutableCollection:支持增加删除item 的 collection。提供了额外的函数,如 add、remove、clear等
5、List: 范性有序集合。
6、MutableList: 支持增删item 的 List
7、Set: 无序并不支持重复 item 的 集合
8、MutableSet: 支持增删item 的 Set
9、 Map:
10、MutableMap: 支持增删 item 的 map
9.1、总数操作符
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: 返回符合给出判断条件的元素总数
assertEquals(3,list.count {it % 2 == 0})
4、fold: 在一个初始值的基础上从第一项到最后一项通过一个函数累计所有的元素
asserEquals(25, list.fold(4) { total, next -> total + next})
5、foldRight: 与 fold 一样,但顺序是从最后一项到第一项。
6、forEach: 遍历所有元素,并执行给定的操作。
list.forEach { println(it) }
7、forEachIndexed: 与 forEach ,同时可得到元素的 Index
list.forEachIndexed { index, value -> println("position $index contains a $value")}
8、max: 返回最大一项,如果没有则返回 null
9、maxBy: 根据给定的函数返回最大的一项,没有返回 null
assertEquals(1, list.maxBy { -it })
10、min
11、minBy
12、none
13、reduce:与fold一样,但没有初始值。通过一个函数从第一项到最后一项进行累计。
assertEquals(21, list.reduce {total, next -> total + next})
14、reduceRight: 顺序从最后一项到第一项
15、sumBy: 返回所有每一项通过函数转换之后的数据的总和。
9.2、过滤操作符
1、drop:返回包含去掉前 n 个元素的所有元素的列表
assertEquals(listOf(5,6), list.drop(4))
2、dropWhile: 返回根据给定函数从第一项开始去掉指定元素的列表
3、dropLastWhile:返回根据给定函数从最后一项开始去掉指定元素的列表
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: 返回从第一个开始符合给定函数条件的元素
9.3、映射操作符
1、flatMap:遍历所有的元素,为每一个创建一个集合,最后把所有集合放在一个集合中。
2、groupBy:返回一个根据给定函数分组后的 map
3、map:返回一个每一个元素根据给定函数转换所组成的list
4、mapIndexed:返回一个每一个元素根据给定的包含元素 index 的函数转换所组成的 list
5、mapNotNull
9.4、元素操作符
1、contains
2、elementAt:返回给定index对应的元素,如果index数组越界则会抛出 IndexOutOfBoundsException
3、elementAtOrElse: 越界则给出默认值
4、elementAtOrNull
5、first
6、firstOrNull
7、indexOf
8、indexofFirst
9、indexOfLast
10、last
11、lastIndexOf
12、lastOrNull
13、single:返回符合给定函数的单个元素,如果没有符合或超过一个,则抛出异常
14、singleOrNull
9.5、生产操作符
1、merge:把两个集合合并为一个新的,相同index的元素通过给定的函数进行合并生成新的元素作为新集合中的一个元素,返回新集合。新集合的大小由最小的那个集合大小决定
2、partition: 把一个给定集合的分割为两个,第一个集合是由原集合每一项元素匹配给定函数条件返回 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:指定函数排序
4、sortDescending:降序
5、sortDescendingBy:指定函数降序