kotlin代码

本周,我试图改进我在Kotlin开发的宠物Android应用程序。 由于我刚开始时对Kotlin刚起步,所以大多数代码看起来就像用Kotlin编写的Java。

从简单开始

这是一个这样的代码片段,它需要初始化模板消息及其参数:

valmessageTemplate:String
valparams:Array<Any>

when(shownCount){
    0->{
        messageTemplate=noItem
        params=arrayOf<Any>()
    }

    1->{
        messageTemplate=itemShowSingle
        params=arrayOf<Any>(totalCount)
    }

    else->{
        messageTemplate=itemShowCount
        params=arrayOf(shownCount,totalCount)
    }
}

M3之后的Kotlin版本不再提供Tuple ,而在stdlib中提供了PairTriple等专门版本。 同样, to()扩展函数可以在不使用构造函数的情况下即时创建此类对。

销毁声明

当函数返回PairTriple或任何数据类时,Kotlin允许立即初始化多个变量。

这是新的改进代码:

val(messageTemplate,params)=when(shownCount){
    0->noItemtoarrayOf<Any>()
    1->itemShowSingletoarrayOf<Any>(totalCount)
    else->itemShowCounttoarrayOf(shownCount,totalCount)
}

stdlib也称为Kotlin的工具带

Android中的一项常见任务是通过ContentValues实例将数据发送到SQLite数据库。 天真的Java端口看起来像以下片段:

valtaskValues=ContentValues()
taskValues.put(T_NAME_COL,task.name)
taskValues.put(T_DESC_COL,task.description)
taskValues.put(T_PRIO_COL,task.priority)
taskValues.put(T_DONE_COL,if(task.done)1else0)
taskValues.put(T_LIST_COL,list.id)

if(task.imagePath!=null){
    taskValues.put(T_IMG_COL,task.imagePath.toString())
}

Kotlin的stdlib提供了许多有趣的功能。

应用()

apply()是对Any类型设置的扩展功能。 它接受一个返回空值的函数作为参数,将其应用于接收者并返回后者。 请注意,在lambda范围内, this是接收者。

让()

let()是在Any类型上设置的另一个扩展函数。 它接受一个转换函数作为参数,并以接收者作为参数调用它。

空安全呼叫操作员

.? 仅当左侧操作数不为null时,运算符才会调用右侧操作数。 这是Kotlin惯用的null检查方法

结合使用它们将提供以下代码:

valtaskValues=ContentValues().apply{
    put(T_NAME_COL,task.name)
    put(T_DESC_COL,task.description)
    put(T_PRIO_COL,task.priority)
    put(T_DONE_COL,if(task.done)1else0)
    put(T_LIST_COL,list.id)
    task.imagePath?.let{put(T_IMG_COL,it.toString())}
}

更进一步

另一个常见的Android任务是读取UI组件中存储的数据:

valid=nameView.tagasLong?

if(id!=null){
    task.id=id
}
安全投

强制转换在Kotlin中使用as运算符进行处理。 但是,可为空和不可为空的类型不属于同一层次结构。 因此,如果将null强制转换为不可为null的类型,则将在运行时引发ClassCastException 。 为了避免这种情况,我们该as? 聪明的演员。

使用let().? 运算符与smart cast结合可产生下一个改进:

(nameView.tagas?Long)?.let{task.id=it}

整个shebang

最后一个通用代码段与查询SQLite数据库有关。 基本上,通常的流程是创建对象,创建游标,对其进行迭代以读取值并从中设置对象的属性。 看起来像这样:

funfindById(id:Long):Task{
    valcursor=readableDatabase.rawQuery("SELECT A LOT FROM TABLE",arrayOf(id.toString()))
    cursor.moveToFirst()
    valname=cursor.getString(1)
    valdescription=cursor.getString(2)
    valimagePath=cursor.getString(3)
    valtask=Task(name,description)

    if(!cursor.isNull(4)){
        valdate=cursor.getLong(4)
        task.alarm=Date(date)
    }

    cursor.close()
    task.id=id

    if(imagePath!=null){
        task.imagePath=Uri.parse(imagePath)
    }

    returntask
}
本地功能

Java中的方法与可见性和作用域有关。 基本上,如果希望某个方法在其他类中不被重用,则可以设置私有可见性。 如果仅在另一个方法中使用此方法,则只会污染类名称空间。 嵌入式函数是一种在另一个函数中声明一个函数以避免这种污染的方法。 Kotlin(以及Scala)允许这样做。

with()

stdlib的另一个有用功能是with()。 任何类型都可用,它有2个参数:第一个是接收器,第二个是转换函数,并在前者上调用后者。

将这些功能与上述某些功能组合在一起可以大大改善代码:

funfindById(id:Long):Task{

    funtoTask(cursor:Cursor):Task{
        with(cursor){
            moveToFirst()
            valname=getString(1)
            valdescription=getString(2)
            valimagePath=getString(3)
            returnTask(name,description).apply{
                if(!isNull(4)){
                    valdate=getLong(4)
                    valalarm=Date(date)
                    this.alarm=alarm
                }

                this.id=id
                imagePath?.let{this.imagePath=Uri.parse(it)}
                close()
            }
        }
     }

    returnreadableDatabase.rawQuery(
            "SELECT A_LOT FROM TABLE",
            arrayOf(id.toString())).let{toTask(it)}
}

结论

学习一种新的编程语言很容易:许多书籍都承诺在21天之内做到这一点。 困难的部分是如何用这种新语言编写惯用代码。 这是一个漫长而艰巨的旅程,需要大量阅读此类惯用代码,自己编写“不良”代码并在多次迭代过程中对其进行改进。

翻译自: https://blog.frankel.ch/code-improvement-kotlin/

kotlin代码

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐