个人使用Kotlin的几种习惯用法

5,877 阅读2分钟

简介

随着kotlin在我的代码中占比越来越大,我觉得自己有必要在一段时间的使用之后总结有哪些好的用法和哪些坏的用法。这篇文章记录了个人习惯了的几个kotlin写法,如果觉得我的这几种用法无论是性能上或是可读性、可维护性上有问题,欢迎和我一起讨论。

几种习惯用法

  • 一、使用?.let代替空判断

    private fun getInfo(jsonObject: JSONObject?): Info? {
        return jsonObject?.let {
            val uri = it.optString("uri")
            val length = it.optString("length")
            Info(uri, length)
        }
    }
    

    这样写和用if判空的写法没有区别,实际上根据这段代码编译出的字节码反编译得到的java代码就是if...else...形式的。这样做的好处在于:

    • 1.var可空属性

      当对象是var可空属性时,即使在判断非空的代码块内也不能把对象当做非空对象,而必须加上!!,导致损失了kotlin提供的空安全。原因是kotlin考虑到多线程问题,即使在判断非空的代码块内var可空属性仍可能被其他线程设置为null。而局部变量和val可空属性就不需要考虑多线程问题,可以再判断非空的代码块内可以把对象当做非空对象。 使用?.let可以解决这个问题,原因是let代码块内部使用的it是接收对象的参数,是局部变量。

    • 2.多重判断中的使用
      // if...else...写法
      private fun testIfElse(): Object? {
              return if (a !== null) {
                  val b = handleA(a)
                  if (b !== null) {
                      handleB(b)
                  } else {
                      null
                  }
              } else {
                  null
              }
          }
      // ?.let写法
      private fun testLet(): Object? {
              return a?.let { handleA(it) }?.let { handleB(it) }
      }
      
  • 二、使用apply做对象的初始化

    return TextView(context).apply {
        text = "test"
        setOnClickListener(onClickListener)
    }
    
  • 三、使用let(apply、takeIf、run...)将整块逻辑分割开来

    File(url).takeIf { it.exists() }
            ?.let {
                JSONObject(NetworkUtils.postFile(SERVER_URL, url))
            }?.takeIf { it.optString("message") == "success" }
            ?.let {
                post(it.optString("result"))
            } ?: mHandler.post { view?.onFail() }
    

    这段代码的功能是上传文件、获得数据再上传数据,使用let这种方法能将这几个部分的逻辑完全分离。

总结

kotlin的语法其实都可以看做java的语法糖,相当于多一层封装,多这一层封装带来性能损失和可读性提高,如何合理使用kotlin的奇妙语法写出让人赏心悦目的代码而又不滥用,这是我以后kotlin开发过程中将持续探索的问题。