Kotlin Module 3
Null safety interview questions
15 interview questions on null safety from Kotlin: short warm-ups, then what each harder question tests, the first step of a good answer and its follow-ups.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is the difference between a?.b and a!!.b in Kotlin, and which should you reach for first?
-
Fresher
What is a smart cast in Kotlin, and when does the compiler refuse to make one?
Answered in the lesson Smart casts, is checks and safe casts
-
Fresher
What is the difference between List<String?> and List<String>? in Kotlin?
Answered in the lesson Nulls inside collections and generics
-
Fresher to mid
What is a platform type in Kotlin, and how should you handle a value that has one?
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A crash report from a booking app shows a NullPointerException with no message, on the line
val berth = bookings[pnr]!!.coach!!.berth!!.number. How do you find out which value was null, and how would you rewrite the line so that the next failure explains itself?- What it tests
- Reading a stack trace from !!, telling a normal missing value from a bug, and choosing between a fallback, an early return and a precondition.
- First step
- Notice what the report cannot tell you: the trace names the line, and that line holds three !!, each of which throws the same exception without a message. So start from the data: take the PNR from the report and check which of the booking, its coach and its berth was missing.
- Follow-ups
-
- Why does the exception have no message?
- Which of the three missing values are normal cases?
- Would the JDK's helpful NullPointerException messages have helped here?
From the lesson Nullable types, safe calls and Elvis
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A function findCustomer(id) sometimes finds nothing. Should it return null, a default customer or throw? Decide for two callers: a checkout API that charges the customer, and a nightly report that counts orders per city.
- What it tests
- Designing a function's contract for a missing value, what each choice costs its callers, and where the decision about a missing value belongs.
- First step
- Ask who can decide what a missing customer means. The function knows only that the id was not found, while the checkout must refuse to charge and the report must still count the order. That points to a nullable return type, with each caller choosing its own branch.
- Follow-ups
-
- When would you throw from findCustomer instead?
- Why not return a default Customer object?
- How would you test both callers?
From the lesson Nullable types, safe calls and Elvis
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
The compiler refuses a smart cast on order.note, a var property, and a colleague silences it with order.note!!.trim() right after the null check. You review the change: when can that line still crash, and what would you ask for instead?
- What it tests
- Why a var property cannot be smart-cast, what !! does to a change between the check and the use, and the fixes that read a value once.
- First step
- Count the reads. The if reads order.note once and the !! line reads it again. Ask what can run between the two reads: another thread, a callback, or any function the code calls in between.
- Follow-ups
-
- Would @Volatile on the property fix it?
- What if note is a val with a custom getter?
- Is order.note?.trim() as safe as a local val?
From the lesson Smart casts, is checks and safe casts
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A partner's booking feed is parsed into a Map<String, Any?> before your code sees it. Design the function that turns one map into a Booking(pnr: String, seats: Int, coupon: String?). Where do is checks, as? and preconditions go, and what does the caller get for a missing or wrong field?
- What it tests
- Turning untyped data into typed values at one boundary, telling normal bad input from bugs, and reporting every bad field rather than the first one.
- First step
- Decide what a bad field is. Partner data varies, so a missing or wrong field is a normal case, not a bug. That rules out letting as or !! throw deep inside the code, and points to a function that returns either a Booking or the list of problems it found.
- Follow-ups
-
- Why not cast each field with as and catch ClassCastException?
- Where would require still belong?
- How would you test it?
From the lesson Smart casts, is checks and safe casts
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A shared helper fun isValidPnr(s: String?): Boolean is called before every use of s, yet the compiler still wants s!! afterwards, and the team has started writing it everywhere. Why does the compiler not see the check, and what would you change?
- What it tests
- What the compiler can know about an argument after a call returns true, what a declared promise about a result costs, and API shapes that make the check and the value one thing.
- First step
- Look at what the compiler can know about s on the line after isValidPnr(s) returned true. Ask what the declaration of isValidPnr says about s, and what the compiler would need to be told to drop the question mark.
- Follow-ups
-
- Would a contract fix it, and what does it cost?
- What would you return instead of a Boolean?
- Why is s!! after the check a problem if the check is right?
From the lesson Smart casts, is checks and safe casts
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An app's API returns List<Order>?, where null was meant to mean "not loaded yet" and an empty list "no orders". A bug report says customers saw "You have no orders" while their orders were still loading. How would you redesign the type, and how would you move the callers over?
- What it tests
- Separating the state of a load from its data, why one nullable type cannot carry two meanings, and changing a type that many callers use without breaking them.
- First step
- Count the states the screen really has: loading, loaded with orders, loaded with none, and failed. A List<Order>? has only two shapes, null and a list, so at least two of those states are being squeezed into one.
- Follow-ups
-
- Why not keep null and document it better?
- Where does an empty list still belong?
- How do you change the type without breaking every caller at once?
From the lesson Nulls inside collections and generics
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A billing job computes daily electricity use as the difference between consecutive meter readings, after replacing each missing reading with 0. One customer's statement shows a day with a negative use, followed by a day as large as the meter's whole count. What happened, and how would you compute and show daily use instead?
- What it tests
- Treating a missing value as a measurement, how one gap corrupts the differences on both sides of it, and reporting what is known instead of inventing it.
- First step
- Write out the readings around the missing day, with the 0 that the job put in its place, and work out the two daily differences that use it. Then ask what a 0 claims about the meter on that day.
- Follow-ups
-
- Why does the total for the week still come out right?
- Should the job carry the last reading forward instead?
- What should the statement show for the days it cannot know?
From the lesson Nulls inside collections and generics
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Write the signature of a generic helper that takes a list whose items may be null and returns the first item that is present, or throws when there is none. Why T & Any rather than a bound T : Any, and when would you choose the bound?
- What it tests
- Reading and writing nullability in generic signatures: an unbounded type parameter, a bound of Any, and the definitely non-nullable type.
- First step
- Start from the callers: they hold List<String?> values, so T must be allowed to be String?. That rules out a bound of Any on T itself, and leaves one question: how the result type says that it is never null.
- Follow-ups
-
- How would you write it with T : Any instead?
- What should the exception say?
- What changes if the helper returns null instead of throwing?
From the lesson Nulls inside collections and generics
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
Java code in your service calls a Kotlin function fun register(name: String) and sometimes passes null. Where exactly does it fail, what does the error tell you, and how would you design the Kotlin side for its Java callers?
- What it tests
- What protects Kotlin code from Java callers, reading the message that results, and choosing parameter types and checks for an API that Java code uses.
- First step
- Start from what Java can see: a method that takes a String, with nothing in the language that says null is not allowed. Then ask what Kotlin can do about a null that arrives anyway, and at which line it can do it.
- Follow-ups
-
- Would it fail differently if register were private?
- Should the parameter be String? instead?
- Is there a compiler option that changes what happens?
From the lesson Platform types and Java nullability
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A Java method returns a List<String> that sometimes holds null items. Kotlin code calls names.map { it.length } on the result and crashes. Where does it fail, why did the compiler not catch it, and what should the Kotlin side do?
- What it tests
- Platform types inside collections, what Kotlin checks about a collection and what it does not, and cleaning Java data where it enters Kotlin.
- First step
- Write down the type Kotlin gives the result: a platform list of platform strings, (Mutable)List<String!>!. Neither the list nor its items carry a decision, so the compiler checks neither, and a null travels until something calls a method on it.
- Follow-ups
-
- Would declaring the result as List<String> have helped?
- What if the Java side is your own code?
- How would you find every such place in a code base?
From the lesson Platform types and Java nullability
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
Your Kotlin services depend on a large Java library, owned by another team, with no nullability annotations, and its values cause most of your NullPointerExceptions. Would you annotate it, wrap it, or declare types at every call? Plan the change.
- What it tests
- Weighing annotations, adapters and types at each call by who owns the code and how often it is called, and rolling out a change across teams without breaking builds.
- First step
- Separate what you control from what you do not. The library's source belongs to another team, so annotating it is a change they make; wrapping it, or deciding at each call, is a change you can make today.
- Follow-ups
-
- How do you get the library's team to annotate it?
- What does the compiler's warn mode buy during the move?
- How do you know that the change worked?
From the lesson Platform types and Java nullability
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes