skip to content

Null Safety

Kotlin's headline feature: the compiler tracks nullability in the type system, gives you operators to navigate it, narrows types automatically after checks, and marks Java values as platform types. Almost every Kotlin interview spends real time here, because it is the reason many teams adopted the language.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

explore

questions

87 · 6 sections

In Kotlin, what is the difference between the types `String` and `String?`, and what does the compiler do differently for each?

level: juniorimportance: must knowfreq 90%
basics
~10 s

String can never hold null; String? can. The compiler rejects assigning null to String, and forces you to handle the null case before using a String? directly.

open as a page

How does Kotlin's approach to absence differ from wrapper-based Option/Maybe types (e.g. Java `Optional`, Scala `Option`, Rust `Option`)?

level: middleimportance: should knowfreq 60%
basics
~10 s

Option/Maybe wrap a value in an extra object you must unwrap. Kotlin instead marks the type itself as nullable, so null stays the plain value — no wrapper, no unwrapping, checked by the compiler.

open as a page

How does nullability interact with generics in Kotlin? Explain what `T`, `T?`, and `T & Any` mean for a type parameter, and how to express a non-null bound.

level: seniorimportance: should knowfreq 30%
basics
~20 s

An unbounded type parameter T can itself be a nullable type, so values of T might be null. To force non-null, bound it with T : Any. Writing T? always allows null; T & Any strips nullability from a T.

open as a page

What is the type of the literal `null` in Kotlin, and how do `Nothing`, `Nothing?`, `Any`, and `Any?` fit into the type hierarchy with respect to nullability?

level: seniorimportance: should knowfreq 35%
basics
~20 s

null's type is Nothing?. Nothing is the empty type at the bottom of every type; Nothing? holds only null. Any? sits at the very top (all values including null); Any is the top of all non-null values.

open as a page

What are the architectural benefits and the limitations of modeling absence in the type system (compile-time) rather than at runtime, especially regarding Java interop and reflection/generics?

level: principalimportance: nice to knowfreq 20%
basics
~20 s

Putting null in the type system catches missing-value bugs at compile time and documents intent for free. The catch: it's compiler-only, so Java code, reflection, and erased generics can slip null past the guarantees at runtime.

open as a page

In Kotlin, what is the default upper bound of an unbounded type parameter like <T>, and what does that imply about whether T can hold null?

level: juniorimportance: must knowfreq 70%
basics
~10 s

An unbounded <T> defaults to the upper bound Any?, which includes null. So T can hold a null value unless you restrict it.

open as a page

What is a nullable receiver in Kotlin, and how does it let String?.isNullOrEmpty() be called on a null value without a NullPointerException?

level: juniorimportance: must knowfreq 70%
basics
~20 s

It is an extension function written on a type that may be null (like String?). Because the function is defined for the null case too, you can call it on null, and inside it checks whether this is null.

open as a page

In Kotlin, what is the difference between the types String and String?, and which one can hold null?

level: juniorimportance: must knowfreq 92%
basics
~10 s

String can never be null; the compiler rejects null for it. String? can hold either a real String or null. The ? means 'this might be null'.

open as a page

Show how `T & Any` is used to override a Java generic method annotated `@NotNull`. Why is it needed there?

level: middleimportance: must knowfreq 30%
basics
~20 s

When a Java method returns a generic value marked @NotNull, Kotlin couldn't express that the return is non-null in an override. T & Any lets the Kotlin override say 'this return is definitely not null'.

open as a page

Inside generic code, how does using T differ from using T? when the parameter is declared <T : Any>? Show how each affects what values are accepted and returned.

level: middleimportance: must knowfreq 60%
basics
~10 s

With <T : Any>, T is always non-null, while T? adds nullability back for that specific use. So T rejects null but T? accepts it, even when T itself cannot be null.

open as a page

What does the Elvis operator ?: do in Kotlin, and what is a typical example of using it?

level: juniorimportance: must knowfreq 80%
basics
~10 s

The Elvis operator ?: gives a fallback value when the left side is null. You write a ?: b: if a is not null you get a, otherwise you get b.

open as a page

What does `value?.let { ... }` do, and what is `it` inside the block?

level: juniorimportance: must knowfreq 80%
basics
~10 s

It runs the block only when value is not null. Inside the block, it is that same value, now guaranteed non-null, so you can use it safely without extra null checks.

open as a page

What does the !! operator do in Kotlin, and what happens at runtime if the value is null?

level: juniorimportance: must knowfreq 80%
basics
~10 s

!! tells the compiler to treat a nullable value as if it is definitely not null. If the value actually is null at runtime, the program crashes with a NullPointerException.

open as a page

What does the safe-call operator ?. do in Kotlin, and what is the type of a?.length when a is a String??

level: juniorimportance: must knowfreq 90%
basics
~20 s

?. only calls the method or reads the property if the value on the left is not null. If it is null, the whole expression is null instead of crashing. So a?.length gives an Int? (a number or null).

open as a page

What is the difference between the `as` and `as?` operators in Kotlin, and what happens at runtime when the value is not of the target type?

level: juniorimportance: must knowfreq 78%
basics
~10 s

as forces a type conversion and crashes with an exception if the value isn't that type. as? tries the same conversion but gives back null instead of crashing when the type doesn't match.

open as a page

Why can you use a variable as non-null after calling requireNotNull(x) or checkNotNull(x), even though the null check happens inside a separate function?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Those standard functions tell the compiler a fact: if they return normally, the argument is not null. So after the call the compiler treats the variable as non-null and lets you use it without ?. or !!.

open as a page

What is a smart cast in Kotlin, and how does it work after an `if (x != null)` or `is` check?

level: juniorimportance: must knowfreq 80%
basics
~10 s

After you check a variable for null or for a type, Kotlin automatically treats it as the checked type inside that block. You can use it without writing an explicit cast.

open as a page

Why does Kotlin let you smart-cast a nullable `val` after a null check but refuse to do the same for a `var`?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A val can never change, so after you check it is not null the compiler trusts it stays not null. A var can be reassigned, maybe to null, so the compiler cannot trust the check still holds.

open as a page

How does smart casting work with early returns and negated checks (e.g. `if (x == null) return`)?

level: middleimportance: must knowfreq 70%
basics
~10 s

If you return early when the value is null, the compiler knows that after that point the value cannot be null, so it smart-casts it to non-null for the rest of the function.

open as a page

Write a custom validation helper that smart-casts its argument to non-null after the call. Explain each part of the contract DSL you use.

level: middleimportance: should knowfreq 40%
basics
~20 s

Add a contract { } block as the first line of the function. Inside, write returns() implies (arg != null). That tells the compiler that whenever the function returns normally, the argument was not null, so callers can use it as non-null.

open as a page

A Java method returns a value Kotlin sees as a platform type (e.g. String!). How do you safely give it a default when it is null, and what does the ?: (Elvis) operator do here?

level: juniorimportance: must knowfreq 78%
basics
~10 s

Use the Elvis operator: val name = javaCall() ?: "unknown". If the left side is null, you get the value on the right. It gives a safe default instead of risking a crash.

open as a page

When you call a Java method from Kotlin, how do @Nullable and @NotNull annotations on that Java method change the type Kotlin sees?

level: juniorimportance: must knowfreq 70%
basics
~20 s

If the Java method is marked @NotNull, Kotlin treats the result as a normal non-null type. If it is @Nullable, Kotlin treats it as nullable and makes you check for null. Without an annotation, Kotlin can't tell.

open as a page

What is a Kotlin platform type, how is it written, and why does calling Java code sometimes risk a NullPointerException even in Kotlin?

level: juniorimportance: must knowfreq 70%
basics
~20 s

When Kotlin calls Java code that doesn't say whether a value can be null, Kotlin can't tell either. It treats the value as a 'platform type' and skips its null checks, so a null can slip through and crash at runtime.

open as a page

At the Java interop boundary, when do you use requireNotNull versus checkNotNull, and how do they differ from the !! operator?

level: middleimportance: must knowfreq 70%
basics
~10 s

requireNotNull checks arguments and throws IllegalArgumentException if null. checkNotNull validates internal state and throws IllegalStateException. Both return the non-null value. !! just throws a generic NullPointerException with no message.

open as a page

Contrast how Kotlin imports a Java method that is un-annotated versus one annotated @NotNull. What changes at compile time and at runtime?

level: middleimportance: must knowfreq 60%
basics
~10 s

Un-annotated, Kotlin uses a flexible platform type and skips null checks, so a hidden null blows up later. With @NotNull, Kotlin imports a strict non-null type and trusts it, checking nullability at compile time.

open as a page

What does `this::myProp.isInitialized` do, and why would you use it on a `lateinit var`?

level: juniorimportance: must knowfreq 55%
basics
~20 s

It checks whether a lateinit property has already been given a value. If you read a lateinit property before it is set, the app crashes; this check lets you ask 'is it set yet?' first and avoid the crash.

open as a page

What is `lateinit var` in Kotlin, and what problem does it solve?

level: juniorimportance: must knowfreq 80%
basics
~10 s

lateinit lets you declare a non-null property without giving it a value right away. You promise to set it later before using it, so you avoid making it nullable.

open as a page

What are the restrictions on what kinds of properties can be declared `lateinit`?

level: middleimportance: must knowfreq 70%
basics
~10 s

It must be a var, not a val. It can't be a nullable type, can't be a primitive like Int or Boolean, and can't have a custom getter or setter.

open as a page

What happens if you read a `lateinit var` before it is assigned, and what exception is thrown?

level: middleimportance: must knowfreq 65%
basics
~10 s

Reading it before you set it throws an error called UninitializedPropertyAccessException. The message tells you which property wasn't initialized.

open as a page

Why can you only call `isInitialized` through `this::prop` from inside the declaring class, and not on another object's lateinit property from outside?

level: middleimportance: should knowfreq 40%
basics
~20 s

The check needs a direct reference to that exact property, which Kotlin only gives you where the property is visible — normally inside the class that declares it. From outside you usually can't form that reference, so you can't call the check.

open as a page