When we automatically convert Java to Kotlin, there are a lot of non-null assertions in the code!! . Or in some cases because of IDE prompts or compilation errors, we added some of our own!! . But using!!!!! IllegalArgumentException: Parameter Specified as non-null is null.

How to avoid!!!!!?

Use? .let/? .apply/? .run

This is the most common method and the preferred method. But when you have more than one variable to null at the same time, or when you need to deal with null logic, this approach is a little more cumbersome, and some new approaches are covered below.

disposable? .let { if (! it.isDisposed) it.dispose() }Copy the code

Replace Var with Val

var mutableString:String? = null
fun run() {
    mutableString = "a"
    printText(mutableString)
}
fun printText(text: String) {
    ...
}Copy the code

Smart cast to ‘String’ is impossible, Because ‘multableString’ is a mutable property that could have been changed by this time :app:compileDebugKotlin FAILED. Because multableString is a Var variable, Kotlin compiles it to avoid Null changes to the variable from multiple threads.

  • Solution 1 is to change the var variable to val

    val mutableString:String = "a"
    fun run() {
        printText(mutableString)
    }Copy the code
  • Solution 2 is to write a new val variable and assign the var variable to it, taking val as an argument

    fun run() { mutableString = "a" val string = mutableString ? : "" printText(string) }Copy the code

Use the Elvis operator

fun run() {
    multableString = "a"
    printText(multableString ?: "")
}Copy the code

The statement lateinit

Declare lateInit to a variable to indicate that it is late to initialize, preferably in a method with a lifecycle such as activity.oncreate.

lateinit var mutableString: String
override fun onCreate(savedInstanceState: Bundle?) {
    multableString = "a"
    printText(mutableString)
}Copy the code

It is important to note that access to an uninitialized lateinit modify the properties of the sell UninitializedPropertyAccessException anomalies

Note: You cannot use LateInit for primitive types. Error ‘Lateinit’ modifier is not allowed on properties of primitive types

lateinit var mutableInt: IntCopy the code

Proxy properties

If you need to do non-null processing for primitive types and so on, you can use proxy attributes.

var mutableInt: Int by Delegates.notNull<Int>()
override fun onCreate(savedInstanceState: Bundle?) {
    mutableInt = 1
}Copy the code

Must read mutableInt only after the initial assignment, or it will throw an IllegalStateException: Property ${Property. The name} should be initialized before the get.

Null and non-null processing

val result = multableString.notNullElse {
    "$it is not null"
} ({ "is null" })Copy the code

The newly developed method notNullElse, nullates a single variable, passes it as a non-empty type when it is not empty, which improves the convenience, and uses a second block when it is empty to return a value. The return value result is also a non-null type. Download the source code here

Multiple values are not null

private var mLinearLayout: LinearLayout? = null ... private fun initView(context: Context) { mLinearLayout = LinearLayout(context) } ... if (tvItem == null) { mLinearLayout!! .addView(childTvItem) } else { mLinearLayout!! .addView(childTvItem, mLinearLayout!! .indexOfChild(tvItem) + 1) }Copy the code

Let is not so useful when we need to evaluate multiple values, but if we do not use let, we will not get a non-null type. In fact, early in the morning we have already judged empty, is there a better way?

allNotNullElse(tvItem, mLinearLayout) { a, b -> b.addView(childTvItem, b.indexOfChild(tvItem) + 1) } ({ mLinearLayout? .addView(childTvItem) })Copy the code

The newly developed method allNotNullElse returns a and b as non-null types, making addView’s use of non-null types easier to use. Download the source code here