AndroidAndroid新优化

kotlin常用函数

2019-08-28  本文已影响0人  android老男孩

扩展函数

声明一个扩展函数,我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀

其实就是通过import指定的路径,把我们自定义的函数作为list,map等一些对象的方法,比在java中封装util更为方法,直接以list.的方式调用

val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // “swap()”内部的“this”会保存“list”的值
//该函数可以被所有的MutableList对象调用
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // “this”对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}

扩展属性

与扩展函数类似,就是对指定对象的属性的一种扩展

val <T> List<T>.lastIndex: Int
    get() = size - 1

伴生对象

Kotlin没有静态成员,伴生对象是kotlin为java静态成员提供替代方案
因为java没有全局变量,一切属性和方法都是在类里面,Kotlin 之所以能抛弃静态成员,主要原因在于它允许包级属性和函数的存在,包级属性和包级函数可以理解为全局常量和工具函数

class MyClass {
    //伴生对象的声明
     companion object {
        @JvmStatic val anonymous = Person("Anonymous")
         fun say() = println("Hello")
    }
}

@JvmStatic 注解只能用在伴生对象里,修饰伴生对象内的属性和函数,用来告诉编译器将属性和函数编译为真正的 JVM 静态成员。需要注意到,如果在伴生对象声明里使用 @JvmStatic 注解,那么没有加该注解的属性和函数将不会被编译为静态成员

委托

委托类实现的printMessage覆盖了原有的实现,有点像java的动态代理

interface Base {
    fun printMessage()
    fun printMessageLine()
}

class BaseImpl(val x: Int) : Base {
    override fun printMessage() { print(x) }
    override fun printMessageLine() { println(x) }
}
//Derived 的超类型列表中的 by-子句表示 b 将会在 Derived 中内部存储, 
//并且编译器将生成转发给 b 的所有 Base 的方法。
class Derived(b: Base) : Base by b {
    override fun printMessage() { print("abc") }
}

fun main() {
    val b = BaseImpl(10)
    Derived(b).printMessage()
    Derived(b).printMessageLine()
}

委托属性

延迟属性

懒加载,初始化代码块,只有第一次加载时,调用,之后就是直接使用 "Hello"的值,
下面打印的结果为computed! Hello Hello

val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main() {
    println(lazyValue)
    println(lazyValue)
}

可观察属性

属性变化时,监听器会收到有关此属性变更的通知

class User {
    var name: String by Delegates.observable("init") {
        prop, old, new ->
        println("$old -> $new")
    }
}

fun main() {
    val user = User()
    user.name = "first"
    user.name = "second"
}

把属性储存在映射中map中

把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中

class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int     by map
}
构造函数接受一个映射参数
val user = User(mapOf(
    "name" to "John Doe",
    "age"  to 25
))
println(user.name) // Prints "John Doe"
println(user.age)  // Prints 25

委托属性在实际应用中,有时候就是对get,set增加了校验,比如判null或者一些其它的判断

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }
 
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}

参考一个sp的写法

调用处
 private val zipCode: Long by DelegatesExt.preference(this, SettingsActivity.ZIP_CODE,
            SettingsActivity.DEFAULT_ZIP)
实现处
object DelegatesExt {
    fun <T> preference(context: Context, name: String,
            default: T) = Preference(context, name, default)
}
class Preference<T>(private val context: Context, private val name: String,
        private val default: T) {

    private val prefs: SharedPreferences by lazy {
        context.getSharedPreferences("default", Context.MODE_PRIVATE)
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T = findPreference(name, default)

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        putPreference(name, value)
    }

    @Suppress("UNCHECKED_CAST")
    private fun findPreference(name: String, default: T): T = with(prefs) {
        val res: Any = when (default) {
            is Long -> getLong(name, default)
            is String -> getString(name, default)
            is Int -> getInt(name, default)
            is Boolean -> getBoolean(name, default)
            is Float -> getFloat(name, default)
            else -> throw IllegalArgumentException("This type can be saved into Preferences")
        }

        res as T
    }

    @SuppressLint("CommitPrefEdits")
    private fun putPreference(name: String, value: T) = with(prefs.edit()) {
        when (value) {
            is Long -> putLong(name, value)
            is String -> putString(name, value)
            is Int -> putInt(name, value)
            is Boolean -> putBoolean(name, value)
            is Float -> putFloat(name, value)
            else -> throw IllegalArgumentException("This type can't be saved into Preferences")
        }.apply()
    }
}

内联函数

关键字inline,一般适合方法循环或者递归调用其它方法,方法进栈出栈次数多,成本比较高
扩展函数使用inline的也比较多,因为这些函数都做为了参数

默认参数

fun foo(title1: Int = 0, title2: Int) { /*……*/ }
foo(title1 = 1)那么title2就是用了默认参数

单表达式函数

也就是单行函数的写法,省略了花括号

fun double(x: Int): Int = x * 2

中缀表示法

标有 infix 关键字的函数也可以使用中缀表示法(忽略该调用的点与圆括号)调用。中缀函数必须满足以下要求:

infix fun Int.shl(x: Int): Int { …… }
// 用中缀表示法调用该函数
1 shl 2
// 等同于这样
1.shl(2)

局部函数

Kotlin 支持局部函数,即一个函数在另一个函数内部,局部函数可以访问外部函数(即闭包)的局部变量

fun dfs(graph: Graph) {
    val visited = HashSet<Vertex>()
    fun dfs(current: Vertex) {
        if (!visited.add(current)) return
        for (v in current.neighbors)
            dfs(v)
    }

    dfs(graph.vertices[0])
}

尾递归函数

这允许一些通常用循环写的算法改用递归函数来写,而无堆栈溢出的风险。 当一个函数用 tailrec 修饰符标记并满足所需的形式时,编译器会优化该递归,留下一个快速而高效的基于循环的版本:

val eps = 1E-10 // "good enough", could be 10^-15
tailrec fun findFixPoint(x: Double = 1.0): Double
        = if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))

等同于下面这种写法

val eps = 1E-10 // "good enough", could be 10^-15

private fun findFixPoint(): Double {
    var x = 1.0
    while (true) {
        val y = Math.cos(x)
        if (Math.abs(x - y) < eps) return x
        x = Math.cos(x)
    }
}

lamda表达式

这些类型具有与函数签名相对应的特殊表示法,即它们的参数和返回值:

 list.forEachIndexed { 
       index, value ->            
}
实现
(index: Int, T)是传入函数的类型 -> Unit 就是实现 
public inline fun <T> Iterable<T>.forEachIndexed(action: (index: Int, T) -> Unit): Unit {
    var index = 0
    for (item in this) 
   //这里是对传入函数的调用,并且返回了index和item,
   //这里调用一次,外边就会响应一次
    action(checkIndexOverflow(index++), item)
}

//传入string和int两个参数,返回string 返回值将取决于函数{}中的逻辑,但必须返回string,但是函数{}只能接收int作为参数
 val repeatFun1: String.(Int) -> String = { times -> "times$times" }
//传入string和int两个参数,返回string 返回值将取决于函数{}中的逻辑,但必须返回string
 val repeatFun2: (a:String,b:Int) -> String = { a,b -> "a$a b$b" }
 //函数{}中的逻辑扩展性很高,repeat重复append自己
 val repeatFun3: String.(Int) -> String = { times ->  this.repeat(times) }

 fun runTransformation(f: (String, Int) -> String): String {
        return f("hello", 3)
 }

::操作符,函数类型的值可以通过其 invoke(……) 操作符调用:f.invoke(x) 或者直接 f(x)。但必须要满足一下要求才可以使用::

val stringPlus: (String, String) -> String = String::plus
val intPlus: Int.(Int) -> Int = Int::plus

println(stringPlus.invoke("<-", "->"))
println(stringPlus("Hello, ", "world!")) 

println(intPlus.invoke(1, 1))
println(intPlus(1, 2))
println(2.intPlus(3)) // 类扩展调用

解构声明

有时把一个对象 解构 成很多变量会很方便

val (name, age) = person
println(name)
println(age)

作用域函数

let,run,with,apply,also,


屏幕快照 2019-08-28 上午11.50.06.png

各个函数执行场景

注意避免过度使用和嵌套过多

简单看几个例子

val numberList = mutableListOf<Double>()
numberList.also { println("Populating the list") }
    .apply {
        add(2.71)
        add(3.14)
        add(1.0)
    }
    .also { println("Sorting the list") }
    .sort()
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)  
优化成
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let { 
    println(it)
} 

参考

https://zhuanlan.zhihu.com/p/26713535

上一篇下一篇

猜你喜欢

热点阅读