First, you should read all about Null Safety in Kotlin which covers the cases thoroughly.

In Kotlin, you cannot access a nullable value without being sure it is not null (Checking for null in conditions), or asserting that it is surely not null using the !! sure operator, accessing it with a ?. Safe Call, or lastly giving something that is possibly null a default value using the ?: Elvis Operator.

For your 1st case in your question you have options depending on the intent of the code you would use one of these, and all are idiomatic but have different results:

val something: Xyz? = createPossiblyNullXyz() // access it as non-null asserting that with a sure call val result1 = something!!.foo() // access it only if it is not null using safe operator, // returning null otherwise val result2 = something?.foo() // access it only if it is not null using safe operator, // otherwise a default value using the elvis operator val result3 = something?.foo() ?: differentValue // null check it with `if` expression and then use the value, // similar to result3 but for more complex cases harder to do in one expression val result4 = if (something != null) { something.foo() } else { ... differentValue } // null check it with `if` statement doing a different action if (something != null) { something.foo() } else { someOtherAction() }

For the "Why does it work when null checked" read the background information below on smart casts.

For your 2nd case in your question in the question with Map , if you as a developer are sure of the result never being null , use !! sure operator as an assertion:

val map = mapOf("a" to 65,"b" to 66,"c" to 67) val something = map.get("a")!! something.toLong() // now valid

or in another case, when the map COULD return a null but you can provide a default value, then Map itself has a getOrElse method:

val map = mapOf("a" to 65,"b" to 66,"c" to 67) val something = map.getOrElse("z") { 0 } // provide default value in lambda something.toLong() // now valid

Background Information:

Note: in the examples below I am using explicit types to make the behavior clear. With type inference, normally the types can be omitted for local variables and private members.

More about the !! sure operator

The !! operator asserts that the value is not null or throws an NPE. This should be used in cases where the developer is guaranteeing that the value will never be null . Think of it as an assert followed by a smart cast.

val possibleXyz: Xyz? = ... // assert it is not null, but if it is throw an exception: val surelyXyz: Xyz = possibleXyz!! // same thing but access members after the assertion is made: possibleXyz!!.foo()

read more: !! Sure Operator

More about null Checking and Smart Casts

If you protect access to a nullable type with a null check, the compiler will smart cast the value within the body of the statement to be non-nullable. There are some complicated flows where this cannot happen, but for common cases works fine.

val possibleXyz: Xyz? = ... if (possibleXyz != null) { // allowed to reference members: possiblyXyz.foo() // or also assign as non-nullable type: val surelyXyz: Xyz = possibleXyz }

Or if you do a is check for a non-nullable type:

if (possibleXyz is Xyz) { // allowed to reference members: possiblyXyz.foo() }

And the same for 'when' expressions that also safe cast:

when (possibleXyz) { null -> doSomething() else -> possibleXyz.foo() } // or when (possibleXyz) { is Xyz -> possibleXyz.foo() is Alpha -> possibleXyz.dominate() is Fish -> possibleXyz.swim() }

Some things do not allow the null check to smart cast for the later use of the variable. The example above uses a local variable that in no way could have mutated in the flow of the application, whether val or var this variable had no opportunity to mutate into a null . But, in other cases where the compiler cannot guarantee the flow analysis, this would be an error:

var nullableInt: Int? = ... public fun foo() { if (nullableInt != null) { // Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time" val nonNullableInt: Int = nullableInt } }

The lifecycle of the variable nullableInt is not completely visible and may be assigned from other threads, the null check cannot be smart cast into a non-nullable value. See the "Safe Calls" topic below for a workaround.

Another case that cannot be trusted by a smart cast to not mutate is a val property on an object that has a custom getter. In this case, the compiler has no visibility into what mutates the value and therefore you will get an error message:

class MyThing { val possibleXyz: Xyz? get() { ... } } // now when referencing this class... val thing = MyThing() if (thing.possibleXyz != null) { // error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter" thing.possiblyXyz.foo() }

read more: Checking for null in conditions

More about the ?. Safe Call operator

The safe call operator returns null if the value to the left is null, otherwise continues to evaluate the expression to the right.

val possibleXyz: Xyz? = makeMeSomethingButMaybeNullable() // "answer" will be null if any step of the chain is null val answer = possibleXyz?.foo()?.goo()?.boo()

Another example where you want to iterate a list but only if not null and not empty, again the safe call operator comes in handy:

val things: List? = makeMeAListOrDont() things?.forEach { // this loops only if not null (due to safe call) nor empty (0 items loop 0 times): }

In one of the examples above we had a case where we did an if check but have the chance another thread mutated the value and therefore no smart cast. We can change this sample to use the safe call operator along with the let function to solve this:

var possibleXyz: Xyz? = 1 public fun foo() { possibleXyz?.let { value -> // only called if not null, and the value is captured by the lambda val surelyXyz: Xyz = value } }

read more: Safe Calls

More about the ?: Elvis Operator

The Elvis operator allows you to provide an alternative value when an expression to the left of the operator is null :

val surelyXyz: Xyz = makeXyzOrNull() ?: DefaultXyz()

It has some creative uses as well, for example throw an exception when something is null :

val currentUser = session.user ?: throw Http401Error("Unauthorized")

or to return early from a function:

fun foo(key: String): Int { val startingCode: String = codes.findKey(key) ?: return 0 // ... return endingValue }

read more: Elvis Operator

Null Operators with Related Functions

Kotlin stdlib has a series of functions that work really nicely with the operators mentioned above. For example:

// use ?.let() to change a not null value, and ?: to provide a default val something = possibleNull?.let { it.transform() } ?: defaultSomething // use ?.apply() to operate further on a value that is not null possibleNull?.apply { func1() func2() } // use .takeIf or .takeUnless to turn a value null if it meets a predicate val something = name.takeIf { it.isNotBlank() } ?: defaultName val something = name.takeUnless { it.isBlank() } ?: defaultName

Related Topics

In Kotlin, most applications try to avoid null values, but it isn't always possible. And sometimes null makes perfect sense. Some guidelines to think about: