skip to content

Factory Functions

listOf, setOf, and mapOf build read-only collections while the mutable* family builds modifiable ones, with helpers like emptyList and listOfNotNull for the common edge cases. The infix to for map entries is the piece everyone remembers.

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

questions

5

How do you create a collection in Kotlin using factory functions like listOf, setOf, and mapOf, and what do they return?

level: juniorimportance: must knowfreq 80%

answer

  1. listOf / setOf / mapOf = read-only
  2. vararg, no 'new' needed
  3. map entries use 'to' infix -> Pair
  4. setOf drops duplicates, keeps first
  5. order preserved (LinkedHashSet/Map)

basics

~10 s

Use listOf(1, 2, 3), setOf(...), or mapOf("a" to 1) to build collections quickly. They give you read-only collections you cannot add to or remove from.

solid answer

~40 s

Kotlin's standard library provides top-level factory functions instead of constructors. listOf(vararg elements) returns a read-only List, setOf(...) returns a read-only Set, and mapOf(vararg pairs) returns a read-only Map. They use vararg, so listOf(1, 2, 3) just works. The returned types are the read-only List/Set/Map interfaces, which expose no add/remove/put methods, so the collection's structure cannot be changed through that reference. For maps, entries are written with the to infix function: mapOf("a" to 1, "b" to 2). Element order is preserved (listOf keeps insertion order; setOf and mapOf are backed by LinkedHashSet/LinkedHashMap). These factories are the idiomatic, concise way to create collection literals in Kotlin.

code

kotlin · 5 lines
kotlin
val list = listOf(1, 2, 2, 3)          // [1, 2, 2, 3]
val set = setOf(1, 2, 2, 3)            // [1, 2, 3]
val map = mapOf("a" to 1, "b" to 2)    // {a=1, b=2}
println(list[0])                       // 1 (index access)
// list.add(4)  // does NOT compile: List has no add

go deeper

for a junior

Can call listOf/setOf/mapOf and knows map entries use 'to'.

for a middle

Explains read-only return types and that no add/remove is exposed; knows setOf dedups.

for a senior

Distinguishes read-only from immutable, knows the LinkedHash backing and order guarantees, and the vararg/Pair mechanics.

for a principal

Frames factory functions as an API-design choice (return the narrowest interface, hide concrete type) and discusses implications for library boundaries.

## What factory functions are Kotlin does not have collection literals like `[1, 2, 3]`. Instead, the standard library (`kotlin.collections`) exposes **top-level factory functions** that you call directly without `new`. They are the idiomatic way to construct collections. ## The read-only trio - `listOf(vararg elements: T): List<T>` — an ordered, indexable collection that may contain duplicates. - `setOf(vararg elements: T): Set<T>` — a collection of unique elements (duplicates dropped, keeping the first occurrence). - `mapOf(vararg pairs: Pair<K, V>): Map<K, V>` — key→value associations with unique keys. All three are declared with **`vararg`**, so you pass elements directly: `listOf(1, 2, 3)`. ```kotlin val nums = listOf(1, 2, 3) // List<Int> val names = setOf("a", "a", "b") // Set<String> = [a, b] val ages = mapOf("Ann" to 30, "Bo" to 25) // Map<String, Int> ``` ## The `to` infix for map entries `mapOf` takes `Pair` values. The **`to`** infix function (`infix fun <A, B> A.to(that: B): Pair<A, B>`) builds a pair, so `"a" to 1` is exactly `Pair("a", 1)`. This is what makes map literals read naturally. ## Read-only, not immutable The declared return types are the **read-only interfaces** `List`, `Set`, `Map`. These interfaces expose no `add`, `remove`, or `put`, so you cannot mutate the structure through that reference. (Read-only is distinct from deep immutability — that is a separate topic.) ## Order guarantees - `listOf` preserves insertion order and allows index access via `get`/`[]`. - `setOf` and `mapOf` preserve insertion order because they are backed by `LinkedHashSet` and `LinkedHashMap`. ## Type inference The element type is inferred from arguments. `listOf(1, 2)` is `List<Int>`; `listOf(1, "x")` becomes `List<Any>` (common supertype). You can also specify it: `listOf<Number>(1, 2L)`.

  • Why does listOf return List rather than ArrayList?
    So the caller gets a read-only view with no add/remove on its surface; the concrete backing type (e.g. an Arrays.ArrayList or singleton) is an implementation detail you should not rely on.
  • What does the 'to' in mapOf actually produce?
    A Pair instance. 'a' to 1 equals Pair("a", 1); mapOf accepts vararg Pair and builds the map from them.

Factory functions are like vending machines: you press a button (call the function) and get a finished, sealed product rather than assembling parts yourself.

saying these in an interview costs you the question

  • Claiming listOf returns a mutable list you can add to
  • Thinking Kotlin has [1, 2, 3] array/list literals
  • Saying setOf keeps duplicates
  • Writing mapOf("a", 1) without the 'to' infix
  • Believing read-only means the elements themselves are immutable

context

open as a page

What is the difference between listOf and mutableListOf (and the other mutable* factories), and when would you use each?

level: middleimportance: must knowfreq 75%

basics

~10 s

listOf gives a read-only list; mutableListOf gives one you can add to and remove from. Use mutable only when you actually need to change the collection after creating it.

open as a page

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

level: middleimportance: should knowfreq 55%

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.

open as a page

Explain the 'to' infix function used in mapOf. What does it produce, and what are its pitfalls?

level: seniorimportance: should knowfreq 50%

basics

~10 s

'to' is a small function that builds a key-value Pair, like "a" to 1. mapOf takes those pairs. It is just a Pair, so it has no special map magic.

open as a page

How does type inference work for factory functions like listOf, and what surprises arise with mixed types or spreading an array?

level: seniorimportance: nice to knowfreq 35%

basics

~10 s

Kotlin guesses the element type from the arguments you pass. Mixing types gives a common supertype like Any. You can pass an existing array into the vararg using the spread operator *.

open as a page