kotlin 踩坑记一

kotlin 都出来一年多了,好多公司依然用起来了,新技术必须学习,废话不多说,开始踩坑。碰到bug问题,现在做一一记录。

碰到的第一个问题:Smart cast to 'Node' is impossible, because 'left' is a mutable property that could have been changed by this time

错误代码如下:

private var scanGroupFragment : ScanGroupFragment ?= null
override fun getFragment(): BaseFragment {
    scanGroupFragment = ScanGroupFragment()
    if (mBundle != null) {
        scanGroupFragment.arguments = mBundle
    }
    return scanGroupFragment

}

原因是可能导致scanGroupFragment为空值。

解决方法一:加!!(不推荐)

override fun getFragment(): BaseFragment {
    scanGroupFragment = ScanGroupFragment()
    if (mBundle != null) {
        scanGroupFragment!!.arguments = mBundle
    }
    return scanGroupFragment!!
}

如下stack上的解决方法: 

  1. Use a local variable with smart cast:

    val node = left
    if (node != null) {
        queue.add(node)
    }
  2. Use a safe call such as one of the following:

    left?.let { node -> queue.add(node) }
    left?.let { queue.add(it) }
    left?.let(queue::add)
  3. Use the Elvis operator with return to return early from the enclosing function:

    queue.add(left ?: return)

    Note that break and continue can be used similarly for checks within loops.

这样就可以编译通过了。

参考:https://stackoverflow.com/questions/44595529/smart-cast-to-type-is-impossible-because-variable-is-a-mutable-property-tha/44596284

https://blog.csdn.net/huangpin815/article/details/79283280

然而,这种解决方式不推荐,会出现异常。看到!!符号。这意味着“你在这里有一个潜在的未处理的KotlinNullPointerException”。

先写解决方案:

private lateinit var scanGroupFragment : ScanGroupFragment
override fun getFragment(): BaseFragment {
    scanGroupFragment = ScanGroupFragment()
    if (mBundle != null) {
        scanGroupFragment.arguments = mBundle
    }
    return scanGroupFragment
}

下面介绍几种方式可以去避免使用!!

① 使用val而不是var

Kotlin让你在语言层面思考不可变性。val是只读的,var是可变的。建议你尽可能多的使用只读属性。它们是线程安全的,并且在函数式编程中很好用。

② 使用lateinit

有时候,我们不能使用不可变属性。这在Android中很常见。对于这种情况,我们使用Kotlin提供的lateinit

!!的写法

private var mAdapter: RecyclerAdapter? = null

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   mAdapter = RecyclerAdapter(R.layout.item_data)
}

fun updateData() {
   mAdapter!!.notifyDataSetChanged()
}

lateinit写法

private lateinit var mAdapter: RecyclerAdapter<>

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   mAdapter = RecyclerAdapter(R.layout.item_data)
}

fun updateData() {
   mAdapter.notifyDataSetChanged()
}

注意:访问非初始化lateinit属性将导致UninitializedPropertyAccessException。

lateinit不能应用于原始数据类型(例如:Int)。对于原始数据类型,我们可以这样使用委托:

private var mNum:Int by Delegates.notNull <Int>()

③ 使用let函数

下面是Kotlin代码中常见的错误


这个可变属性在空检查后不能被改变。许多人用下面这种方式解决:

private var mPhotoUrl: String? = null

fun uploadClicked() {
    if (mPhotoUrl != null) {
        uploadPhoto(mPhotoUrl!!)
    }
}

但是可以用let函数更优雅的解决这个问题:

private var mPhotoUrl:String?=null
fun uploadClicked(){
    mPhotoUrl?.let{uploadPhoto(it)}
}

④ 创建全局函数来处理更复杂的内容

let是一个简单的空检查的替代品,但是会有更复杂的情况。如:

if(name!=null&&address!=null{
    upload(name!!,address!!)
}

你可以嵌套两个let,但是可读性会很差。这时候我们用下面这种方式来写:

ifNotNull(name,address){
    name,address->upload(name,address)
}

封装的方法

fun <T1,T2> ifNotNull(value1:T1?,value2:T2?,bothNotNull:(T1,T2)->(Unit)){
    if(value1!=null&&value2!=null){
        bothNotNull(value1,value2)
    }
}

⑤ 使用?:操作符

fun getName():String{
    if(name!=null){
        return name!!
    }else{
        return "android coder"
    }
}

替代的方法:

fun getName():String{
    return name?:"android coder"
}

⑥ 自定义错误信息

使用内置函数requireNotNull或checkNotNull处理异常信息。

upload(intent.getStringExtra("address")!!)

替代方法:

upload(requireNotNull(intent.getStringExtra("address"),{"'address'参数为空!"})

参考:https://blog.csdn.net/xiaoluoli88/article/details/78082311

ok以上便解决完成了。

猜你喜欢

转载自blog.csdn.net/kdsde/article/details/82527884