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上的解決方法:
-
Use a local variable with smart cast:
val node = left if (node != null) { queue.add(node) }
-
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)
-
Use the Elvis operator with
return
to return early from the enclosing function:queue.add(left ?: return)
Note that
break
andcontinue
can be used similarly for checks within loops.
這樣就可以編譯通過了。
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以上便解決完成了。