Kotlin之旅

Kotlin的高阶函数与泛型

2018-04-07  本文已影响14人  墙角的牵牛花

来一个demo:带返回函数的函数

data class Person (
    val firstName :String,
    val lastName :String,
    val phoneNumber:String?

)

class ContactListFilters{
var prefix:String=""
var onlyWithNumber:Boolean=false
fun getPredicate():(Person) -> Boolean{
    val startsWithPrefix={
        p: Person ->
        p.firstName.startsWith(prefix)||p.lastName.startsWith(prefix)
    }
    if (!onlyWithNumber){
        return startsWithPrefix
    }
    return {
        startsWithPrefix(it) && it.phoneNumber!=null
    }
}
}

fun main(args: Array<String>) {
val contacts= listOf(Person("dsfd","ddfs","112233"),
        Person("kjk","wqrre","65644"),
        Person("awqq","pioi",null)
        )

val contactListFilters=ContactListFilters()
with(contactListFilters){
    prefix="kj"
    onlyWithNumber=true
}

println(contacts.filter(
        contactListFilters.getPredicate()
))
}

Lambda筛选demo

/**
 *
 * @author ll
 * @Description:记录站点数据
 * @date Created in 2018/04/07 09:55 AM
 */
data class SiteVisit (
    val path:String,//路径
    val duration:Double,//访问时长
    val os:OS //系统
)

enum class OS{
WINDOWS,LINUX,MAC,IOS,ANDROID
}

计算Windows时间

 val log= listOf(
        SiteVisit("/",34.0,OS.WINDOWS),
        SiteVisit("/dfdf",22.0,OS.MAC),
        SiteVisit("/dfgg",12.0,OS.WINDOWS),
        SiteVisit("/ryyy",8.0,OS.IOS),
        SiteVisit("/wtyty",16.3,OS.ANDROID)
)

//Windows平均访问时间
val avgWindows=log
        .filter { it.os==OS.WINDOWS }
        .map (SiteVisit::duration )
        .average()

println(avgWindows)

抽取公共函数:

fun List<SiteVisit>.avgDurationFor(os:OS)=
    filter { it.os==os }
            .map (SiteVisit::duration)
            .average()

//Windows
println(log.avgDurationFor(OS.WINDOWS))

只要移动平台(Android 和 IOS数据)

  val avgMobilePlatform=log
        .filter { it.os in setOf(OS.IOS,OS.ANDROID) }
        .map (SiteVisit::duration)
        .average()

println(avgMobilePlatform)

显然需要更新公共函数了

fun List<SiteVisit>.avgDuration(predicate: (SiteVisit) -> Boolean)=
    filter(predicate)
            .map(SiteVisit::duration)
            .average()

测试:

    //Windows
println(log.avgDuration { it.os==OS.WINDOWS })

//mobile platform
println(log.avgDuration { it.os==OS.IOS || it.os ==OS.ANDROID })

println(log.avgDuration { it.os==OS.IOS && it.path =="/ryyy" })

内联函数inline:消除lambda的开销

inline fun<T> synchronized(lock: Lock, action:() ->T) :T{
lock.lock()
try {
    return action()
} finally {
    lock.unlock()
}
}

fun foo(l:Lock){
println("before sync")
synchronized(l){
    println("Action")
}
println("after action")
}


 /**
 *函数类型做参数,不是lambda,inline失效
 */
class LockOwner(val lock:Lock){
fun runUnderLock(body:() ->Unit){
    synchronized(lock,body)
}
}

class LockOwner2(val lock:Lock){
 fun _runUnderLock_(body: () -> Unit){
   lock.lock()
   try {
       body()
   } finally {
       lock.unlock()
   }
  }
}

kotlin中,filter,map函数被声明为内联函数。当出现大量数据处理时,可以通过 在链式后加asSequence(),用序列代替集合,但kotlin建议在处理大数据时用。

inline只能提高带有lambda参数的函数的性能.

java中try-with-resources在kotlin中的替代。

//java代码
 static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader bufferedReader=new BufferedReader(new FileReader(path))){
        return bufferedReader.readLine();
    }
}

//kotlin中使用use代替,use在kotlin中是内联函数
fun readFirstLineFromFile(path:String):String{
BufferedReader(FileReader(path)).use { 
    br -> return br.readLine()
}
}

lambda中的返回语句

data class Person2(val name: String ,val age:Int)

fun lookFofJim(people :List<Person2>){
for (person in people){
    if (person.name=="Jim") {
        println("找到了")
        return
    }
}
println("jim 没找到")
}

fun main(args: Array<String>) {
val people= listOf(Person2("fdaaf",34), Person2("trrt",73))
lookFofJim(people)
}

forEach依旧适用
people.forEach {
    if (it.name=="Jim") {
        println("找到了")
        return
    }
}

引入便签局部返回:@一定要有,边签名任意

fun lookFofJim2(people :List<Person2>){

people.forEach label@{
    if (it.name=="Jim") {
        println("找到了")
        return@label
    }
}
//总会执行
println("jim ...")
}

函数名也可以作为标签

fun lookFofJim(people :List<Person2>){
   /* for (person in people){
    if (person.name=="Jim") {
        println("找到了")
        return
    }
}
*/
people.forEach {
    if (it.name=="Jim") {
        println("找到了")
        return@forEach
    }
}
println("jim 没找到")
}

注意,当匿名函数中有return时,返回最近的匿名函数

fun lookFofJim3(people :List<Person2>){
people.forEach(fun(person) {
    if (person.name=="trrt") {
        println("找到了")
        return
    }
})
//总会执行
println("jim ...")
}

此时return是从fun(person)返回。

泛型:Kotlin泛型要求类型实参被显示地说明,或者能被编译器推导出来。

fun <T : Number> oneHalf(value :T) :Double{
return value.toDouble()/2.0
}

val nums= oneHalf(65.32)
println(nums)

fun <T: Comparable<T>> max (first:T,second:T):T{
    return if (first>second) first else second
// return if (first.compareTo(second)>0) first else second
}

println(max(23,546))

参数约定:
fun<T> ensureTrailingPeriod(seq:T) where T:CharSequence,T:Appendable{
if(!seq.endsWith('.')){
    seq.append('.')
}
}

val hello=StringBuilder("fafd fafddadf hello")
ensureTrailingPeriod(hello)
println(hello)

形参可空
class Processor<T> {
fun process(value :T){
    value?.hashCode()
}
}

val nullProcess=Processor<String?>()
nullProcess.process(null)

Any代替Any?形参非空
class Processor2<T : Any>{
fun process(value : T){
    value.hashCode()
}
}

声明带实例化参数的函数
inline fun <reified T> isA(value: Any) =value is T
println(isA<String>("ffdafadfadfadfadfd"))
结果:true

标准库函数:filterIsInstance
val items= listOf("faafd","fdf",122,"fddf1","113423")
println(items.filterIsInstance<String>())

关于reified。带reified类型参数的inline函数不能再java中调用。普通的inline可以被调用,但不能被内联。
filterIsInstances被标记为inline,但它并不期望lambda作为实参 。
目前,还不能把类,属性和非内联函数的类型参数标记为reified。当lambda因为性能被内联时,可以使用noinline标记。
.

  inline fun<reified T : Activity> Context.startActivity(){
    val intent= Intent(this,T::class.java)
    startActivity(intent)
}
Handler().postDelayed({
        startActivity<MainActivity>()
    },3000)

一个编译器通过不了的demo

fun addAnswer(list: MutableList<Any>){
list.add(43)
}

 val strings= mutableListOf("adf","dfadf")
 addAnswer(strings)

kotlin中List是只读集合
超类型概念:A是B的子类型,那么B就是A的超类型。
非空类型A是可空类型A?的子类型,但反过来不是。
不变型:对于任意类型A和B,MutableList<A>既不是MutableList<B>的子类型,也不是超类型,它就被称为该类型参数是不变型的。
协变:如果A是B的子类型,那么List<A>是List<B>的子类型,这样的类或者接口被称为协变。声明协变用out关键字。
逆变:反转子类型化关系。in关键字。

interface Produce<out T>{
fun produce():T
 }

interface Function1<in p,out R>{
operator fun invoke(p:p) :R
}
上一篇下一篇

猜你喜欢

热点阅读