Question

How to Copy or Clone a List in Kotlin

kotlinlistcopy

Question

How can I copy a list in Kotlin?

For example, I am currently using:

val selectedSeries = mutableListOf<String>()
selectedSeries.addAll(series)

Is there a simpler or more idiomatic way to create a copy of a list in Kotlin?

Short Answer

By the end of this page, you will understand how to copy lists in Kotlin, when to use toList() or toMutableList(), the difference between read-only and mutable lists, and what it really means to make a shallow copy of a collection.

Concept

In Kotlin, copying a list usually means creating a new list object that contains the same elements as an existing list.

This matters because you often want to avoid changing the original list by mistake. For example, if one part of your program modifies a list, you may not want those changes to affect another part.

The most common ways to copy a list in Kotlin are:

val copy1 = original.toList()
val copy2 = original.toMutableList()

These create a new collection containing the same items.

Read-only vs mutable lists

Kotlin distinguishes between:

  • List<T>: read-only view
  • MutableList<T>: can be changed

So the copy method you choose depends on what you need:

  • Use toList() when you want a read-only copy
  • Use toMutableList() when you want a copy you can change

Important detail: shallow copy

List copying in Kotlin is usually a shallow copy.

That means:

  • the list container is new
  • the elements inside are the same references if they are objects

Example:

data class User(var name: String)

val original = mutableListOf(User("Ava"))
val copied = original.toMutableList()

copied[0].name = "Liam"

println(original[0].name) // Liam

Even though the list was copied, both lists still refer to the same User object.

That is why understanding copying is important in real programs: sometimes you only need a new list container, and sometimes you need to also copy each object inside it.

Mental Model

Think of a list like an egg carton.

  • The carton is the list itself.
  • The eggs are the elements inside it.

When you use toList() or toMutableList(), Kotlin gives you a new carton, but usually puts the same eggs into it.

So:

  • changing the carton structure, such as adding or removing eggs, affects only that new carton
  • changing an egg itself affects both cartons if they hold the same egg object

This is the key idea behind shallow copying.

Take Quiz

Syntax and Examples

The most idiomatic Kotlin ways to copy a list are:

val readOnlyCopy = original.toList()
val mutableCopy = original.toMutableList()

Example 1: Copy as read-only

val series = listOf("Dark", "Lost", "Sherlock")
val copiedSeries = series.toList()

println(copiedSeries) // [Dark, Lost, Sherlock]

Use this when you only need to read values.

Example 2: Copy as mutable

val series = listOf("Dark", "Lost", "Sherlock")
val selectedSeries = series.toMutableList()

selectedSeries.add("Severance")

println(series)         // [Dark, Lost, Sherlock]
println(selectedSeries) // [Dark, Lost, Sherlock, Severance]

Here, selectedSeries is a new mutable list, so adding an item does not change series.

Example 3: Your current approach

val selectedSeries = mutableListOf<String>()
selectedSeries.addAll(series)

This is valid and common. A shorter idiomatic version is:

val selectedSeries = series.toMutableList()

Example 4: Copy with transformation

Sometimes you want to copy and change values at the same time:

val names = listOf("anna", "ben", "cara")
val upperNames = names.map { it.uppercase() }

println(upperNames) // [ANNA, BEN, CARA]

This creates a new list with transformed values.

Step by Step Execution

Consider this example:

val original = mutableListOf("A", "B", "C")
val copy = original.toMutableList()
copy.add("D")

println(original)
println(copy)

Step by step

  1. original is created as a mutable list:

    ["A", "B", "C"]
    
  2. copy = original.toMutableList() creates a new mutable list with the same elements.

    At this point:

    • original = ["A", "B", "C"]
    • copy = ["A", "B", "C"]
  3. copy.add("D") adds a new element only to copy.

  4. Final result:

    • original = ["A", "B", "C"]
    • copy = ["A", "B", "C", "D"]

Output

[A, B, C]
[A, B, C, D]

This shows that the list structure was copied successfully.

Real World Use Cases

Copying lists is useful in many real programs.

UI state updates

In Android or desktop apps, you may copy a list before modifying it so the original UI state stays unchanged.

val updatedItems = currentItems.toMutableList()
updatedItems.add(newItem)

Filtering user selections

If a user selects items from a master list, you may want a separate editable copy.

val selectedProducts = allProducts.toMutableList()

API data processing

You might receive a list from a repository layer and copy it before sorting or modifying it.

val sortedUsers = users.toMutableList()
sortedUsers.sortBy { it.name }

Defensive programming

Sometimes you copy incoming collections so outside code cannot accidentally affect your internal state.

class Report(items: List<String>) {
    private val safeItems = items.toList()
}

Batch operations

A script may duplicate a list before removing invalid items, while preserving the original input for logging or auditing.

Take Quiz

Real Codebase Usage

In real Kotlin projects, developers often use list copying as part of safer state management and cleaner function design.

Common pattern: make a mutable working copy

A common workflow is:

val workingList = source.toMutableList()
workingList.removeIf { it.isBlank() }

This keeps the original data unchanged.

Defensive copies in constructors and setters

When classes receive collections from outside, developers often copy them:

class Playlist(songs: List<String>) {
    private val songsCopy = songs.toList()
}

This reduces accidental shared state.

Early-return and validation workflows

A list may be copied only after validation passes:

fun prepareTags(tags: List<String>?): List<String> {
    if (tags == null) return emptyList()
    if (tags.isEmpty()) return emptyList()
    return tags.toList()
}

Copy before sorting

Sorting a mutable copy is common when the original order must remain intact:

val sorted = results.toMutableList()
sorted.sortBy { it.score }

Immutable-style updates

Even in codebases that prefer immutability, a new list is often created from an old one:

val newList = oldList.toMutableList().apply {
    add("new item")
}

This pattern is common in state reducers and view models.

Common Mistakes

1. Assuming assignment creates a copy

This is a very common mistake.

val original = mutableListOf("A", "B")
val copy = original
copy.add("C")

println(original) // [A, B, C]

copy = original does not create a new list. Both variables point to the same list.

2. Using toList() and expecting a mutable list

val original = listOf("A", "B")
val copy = original.toList()
// copy.add("C") // Error

Use toMutableList() if you need to add or remove items.

3. Forgetting that copies are usually shallow

data class Item(var value: Int)

val original = mutableListOf(Item(1))
val copy = original.toMutableList()
copy[0].value = 99

println(original[0].value) // 99

The list is copied, but the Item object is shared.

4. Creating an empty list and then calling addAll() unnecessarily

Your original code works:

val selectedSeries = mutableListOf<String>()
selectedSeries.addAll(series)

But if you simply want a copy, this is shorter:

val selectedSeries = series.toMutableList()

5. Confusing read-only with truly immutable

List<T> in Kotlin is read-only from that reference, but the underlying data may still come from a mutable collection elsewhere.

Be careful when sharing collections across different parts of your code.

Comparisons

ApproachWhat it doesMutable?Typical use
val b = aCopies the reference onlySame as originalWhen you intentionally want the same list
a.toList()Creates a new read-only listNoSafe reading, defensive copy
a.toMutableList()Creates a new mutable listYesModify the copy without changing the original
mutableListOf<T>().apply { addAll(a) }Creates a mutable copy manuallyYesLess concise alternative
a.map { it }Creates a new list by iteratingUsually read-only resultUseful when also transforming values

toList() vs toMutableList()

MethodBest whenCan add/remove items?
toList()You only need to read valuesNo
toMutableList()You need to update the copied listYes

Copying a list vs deep copying objects

Type of copyNew list container?New element objects?
Shallow copyYesNo
Deep copyYesYes

Kotlin's standard list copy methods usually perform a shallow copy.

Take Quiz

Cheat Sheet

// Read-only copy
val copy1 = original.toList()

// Mutable copy
val copy2 = original.toMutableList()

// Manual mutable copy
val copy3 = mutableListOf<String>()
copy3.addAll(original)

Rules

  • val b = a does not copy the list
  • toList() returns a read-only list view/copy for normal usage
  • toMutableList() returns a mutable copy
  • Standard list copying is usually shallow
  • If elements are mutable objects, both lists can still point to the same objects

Quick choice guide

  • Need to read only: toList()
  • Need to modify the copy: toMutableList()
  • Need changed values too: map { ... }

Example

val original = listOf("x", "y")
val copy = original.toMutableList()
copy.add("z")

Edge case

If the list contains mutable objects, copying the list does not clone the objects inside it.

FAQ

How do I copy a list in Kotlin?

Use toList() for a read-only copy or toMutableList() for a mutable copy.

What is the idiomatic way to clone a list in Kotlin?

The most idiomatic approach is usually:

val copy = original.toMutableList()

or

val copy = original.toList()

Does val copy = original make a new list?

No. It only copies the reference, so both variables point to the same list.

What is the difference between toList() and toMutableList() in Kotlin?

toList() gives you a read-only list. toMutableList() gives you a list you can change.

Does copying a list in Kotlin also copy the objects inside it?

No, not usually. Standard copying is shallow, so object elements are shared.

Is addAll() wrong for copying a list?

No. It works correctly. It is just more verbose than toMutableList() when your goal is simply to copy the list.

How do I make a deep copy of a list in Kotlin?

You must copy each element too, usually with map and a copy operation if the objects support it.

data class User(val name: String)
val deepCopy = users.map { it.copy() }
Take Quiz

Mini Project

Description

Build a small Kotlin program that manages a list of favorite TV series. The program should start with an original list, create a separate copy for user-selected series, then modify only the copied list. This demonstrates the practical difference between referencing a list and creating an actual copy.

Goal

Create a copied list that can be changed without affecting the original list.

Requirements

  1. Create an original list of at least three series names.
  2. Make a mutable copy of that list.
  3. Add one new series to the copied list.
  4. Print both the original list and the copied list.
  5. Show that the original list stays unchanged.
Take Quiz

Keep learning

Related questions

View more