Null Safety Quiz

KOTLIN › Language Idioms

What is the value and type of b?.length when b is declared as val b: String? = null?

Answer: null of type Int?

A safe call short-circuits to null when the receiver is null, and the result type of ?. is nullable, so the expression is null typed as Int?.

Given val len = name!!.length where name is null, what happens?

Answer: A NullPointerException is thrown at runtime

The !! operator throws a NullPointerException at runtime whenever the value it is applied to is null.

Which expression safely casts obj to String, yielding null instead of an exception if it is not a String?

Answer: obj as? String

as? is the safe cast: it returns null on failure (result type String?), whereas as throws ClassCastException, is is a boolean check, and !! does not perform a cast.

Why can a Kotlin call on a Java method's return value still throw a NullPointerException even with no !! in sight?

Answer: It’s a platform type with unknown nullability, so checks are relaxed

Unannotated Java types become platform types (T!); the compiler trusts you and omits null checks, so an actually-null value throws at runtime.

Which idiom returns the string's length, or 0 when the nullable string s is null?

Answer: s?.length ?: 0

s?.length yields Int? (null when s is null), and the elvis operator then substitutes 0 for that null. s!!.length would throw, and s.length does not compile on a nullable.

Inside if (x != null) { ... }, why can you call x.length without a safe call when x is String?

Answer: The compiler smart-casts x to a non-null String there

After a null check on a stable value, the compiler smart-casts x to the non-null type String for the scope where the check holds, so member access needs no operator.

What does user?.let { sendEmail(it.email) } do when user is null?

Answer: Skips the let block entirely and evaluates to null

The safe call means let is only invoked when user is non-null; when user is null the whole expression short-circuits to null and the block never runs.

Why can you call s.isNullOrEmpty() directly on a value of type String? without any safe call or prior null check?

Answer: isNullOrEmpty is an extension on String?, so a null this is ok

Functions like isNullOrEmpty() and isNullOrBlank() are declared as extensions on a nullable receiver, so the receiver may be null and the function body handles that case itself.

Given val config: String? = ..., what does requireNotNull(config) return and how does it fail?

Answer: Returns non-null String; throws IllegalArgumentException if null

requireNotNull returns the value as its non-null type and throws IllegalArgumentException when the argument is null; the sibling checkNotNull throws IllegalStateException instead.

Given val nums: List<Int?>, which call yields a List<Int> with the nulls removed and the element type narrowed to non-null?

Answer: nums.filterNotNull()

Only filterNotNull() changes the static element type to the non-null Int; filter and filterNot keep the declared List<Int?> type because a runtime predicate does not refine the element type.

In val token: String = header ?: return, where header is String?, why is token typed as non-null String?

Answer: Because return is Nothing, so ?: keeps the left side’s non-null type

The right operand return has type Nothing, a subtype of every type, so the combined elvis expression takes the non-null type of the left operand, leaving token as String.

How does the equality expression a == b behave in Kotlin when a is null?

Answer: It does a null-safe structural check, returning a Boolean, no NPE

The == operator compiles to a null-safe equals call (roughly a?.equals(b) ?: (b === null)), so it handles null receivers and returns a Boolean without throwing.

Why does the compiler refuse to smart-cast a top-level mutable var x: String? to String inside if (x != null) { x.length }?

Answer: Because a mutable var can change after the check, so non-null can’t be guaranteed

For a mutable (non-local) var the value could change after the null check, so the compiler cannot prove it remains non-null and declines the smart cast; copy it into a local val or use ?.let.

Back to Null Safety