skip to content

When and why would you use emptyList()/emptySet()/emptyMap() and listOfNotNull() instead of plain listOf?

level: middleimportance: should knowfreq 55%

answer

  1. emptyList() = typed empty, usually a singleton
  2. use emptyList() as a safe default/return
  3. listOfNotNull strips nulls -> List<T> non-null
  4. setOfNotNull exists; no mapOfNotNull
  5. listOfNotNull(x) = [] or [x]

basics

~10 s

emptyList() gives a typed empty collection (often a shared singleton). listOfNotNull(a, b, c) builds a list but skips any null arguments, so you do not get nulls in the result.

solid answer

~40 s

emptyList()/emptySet()/emptyMap() return read-only empty collections. They are generic (you supply the element type, usually via inference) and typically return a shared, allocation-free singleton, so they are the efficient way to express 'no elements' — better than listOf() with no arguments for clarity and as a default/return value. listOfNotNull(vararg elements: T?): List<T> builds a list from the arguments but filters out every null, returning a List<T> (non-null element type). It is ideal for assembling a list from optional values without manual null checks or filterNotNull afterwards. setOfNotNull exists too. Common uses: returning emptyList() as a safe default, and listOfNotNull(header, body, footer) where some parts may be absent. Both keep your code null-safe and concise.

code

kotlin · 7 lines
kotlin
fun config(): List<String> = source() ?: emptyList()

val a: String? = null
val b = "two"
val c: String? = "three"
val result = listOfNotNull(a, b, c)  // ["two", "three"] : List<String>
val single = listOfNotNull(maybe())  // [] or [value]

go deeper

for a junior

Knows emptyList() makes an empty list and listOfNotNull drops nulls.

for a middle

Explains the non-null result type of listOfNotNull and using emptyList() as a default return value.

for a senior

Knows the singleton/allocation-free nature of empty* and chooses listOfNotNull over filterNotNull for clarity and type.

for a principal

Discusses these as null-safety and allocation-hygiene idioms across APIs and when defaults vs nullable returns are appropriate.

## emptyList / emptySet / emptyMap These factories return a **read-only empty collection** of the requested element type: ```kotlin val xs: List<String> = emptyList() val ys = emptySet<Int>() val zs = emptyMap<String, Int>() ``` Key points: - The element type comes from **inference** or an explicit type argument (`emptyList<Int>()`). - The implementation typically returns a **shared singleton** (e.g. an internal `EmptyList` object), so calling it repeatedly allocates nothing. That makes it the idiomatic default value or empty return. - Prefer `emptyList()` over `listOf()` for the empty case: it reads as intentional and is the canonical 'no elements' expression. Great as a safe default: ```kotlin fun tags(): List<String> = lookup() ?: emptyList() ``` ## listOfNotNull Signature: `fun <T : Any> listOfNotNull(vararg elements: T?): List<T>`. It takes possibly-null arguments and **filters out every null**, returning a `List<T>` whose element type is **non-null**. This removes the need for manual `if`/`filterNotNull`. ```kotlin val header: String? = maybeHeader() val footer: String? = null val lines: List<String> = listOfNotNull(header, "body", footer) // only the non-null values survive; result is List<String>, not List<String?> ``` Useful patterns: - Assembling a list from optional pieces. - A single non-null value or nothing: `listOfNotNull(value)` is `[]` or `[value]` — a tidy `Optional`-like construct. There is also **`setOfNotNull`** with the same null-filtering behavior. (There is no `mapOfNotNull`.) ## Why these over alternatives - `emptyList()` vs `listOf()`: clearer intent, canonical empty, singleton-backed. - `listOfNotNull(a, b)` vs `listOf(a, b).filterNotNull()`: shorter, allocates one list, and gives the non-null element type directly.

  • Why prefer emptyList() over listOf() for an empty return?
    It reads as deliberately empty and is backed by a shared singleton (no allocation), making it the canonical 'no elements' value.
  • What is the element type of listOfNotNull("a", null, "b")?
    List<String> — the nulls are filtered and the result type is non-null T, not T?.

listOfNotNull is a bouncer at the door: null arguments are turned away, only real values get into the list.

saying these in an interview costs you the question

  • Thinking listOfNotNull returns List<T?> with nulls kept
  • Claiming emptyList() allocates a new object each call
  • Not realizing emptyList() needs a known element type
  • Reaching for filterNotNull when listOfNotNull is simpler
  • Inventing mapOfNotNull (it does not exist)

context