Kotlinで List に要素を追加しようとして、
add()が使えない- コンパイルエラーになる
- Javaと同じ感覚で書けない
と戸惑う人は非常に多くいます。
これは Kotlin の List が Javaとは設計思想そのものが違う ためです。
この記事では、
- Kotlinの
ListとMutableListの本当の違い - 要素を追加する正しい方法
- 実務で安全に使える設計パターン
を段階的に解説します。
目次
KotlinのListは「2種類」ある
Kotlinでは、Listは明確に2種類に分かれています。
| 型 | 特徴 | 要素追加 |
|---|---|---|
List<T> | 読み取り専用(変更操作を持たない) | ❌ |
MutableList<T> | 変更可能 | ✅ |
ここで重要なのは、List<T> は 「不変(immutable)」を保証する型ではない という点です。
正確な理解
List:この参照からは 追加・削除などの変更操作ができないMutableList:変更操作ができる
listOf() で作ったListに追加できない理由
val list = listOf(1, 2, 3)
list.add(4) // コンパイルエラー
これは、
listOf()が返す型がListListにはadd()メソッドが存在しない
という 型の問題 です。
「中身が変更不可能だから」ではなく「変更操作を提供しない型だから」追加できません。
要素を追加したいなら MutableList を使う
基本形
val list = mutableListOf(1, 2, 3)
list.add(4)
println(list) // [1, 2, 3, 4]
インデックスを指定して追加
val list = mutableListOf("A", "C")
list.add(1, "B")
println(list) // [A, B, C]
複数要素をまとめて追加
val list = mutableListOf(1, 2)
list.addAll(listOf(3, 4, 5))
println(list) // [1, 2, 3, 4, 5]
List に「追加したい」場合の正しい考え方
List は変更できないため、新しいListを作る という発想に切り替えます。
val list = listOf(1, 2, 3)
val newList = list + 4
println(newList) // [1, 2, 3, 4]
+ 演算子の特徴
- 元のListは変更しない
- 新しいListを返す
- 要素1つでも、List同士でも使える
val list1 = listOf(1, 2)
val list2 = listOf(3, 4)
val result = list1 + list2
// [1, 2, 3, 4]
+ を使うときの注意点
+ は便利ですが、毎回新しいListを生成する ため、大量の追加には向きません。
var list = emptyList<Int>()
repeat(10_000) { i ->
list = list + i
}
このようなケースでは、
- 内部では
MutableList - 完成後に
Listとして扱う
という設計が適しています。
イテレーション中に add() してはいけない理由
val list = mutableListOf(1, 2, 3)
list.forEach {
list.add(it * 10)
}
このコードは、
- 実行時例外(
ConcurrentModificationException) - 未定義な挙動
を引き起こす可能性があります。
正しい書き方
val list = mutableListOf(1, 2, 3)
val newItems = list.map { it * 10 }
list.addAll(newItems)
走査中のコレクション構造を変更しない のが原則です。
「valなのにaddできる」理由
val list = mutableListOf(1, 2)
list.add(3) // OK
val は 参照の再代入を禁止するだけ です。
val:別のListを代入できない- 中身(MutableList)の変更は可能
list = mutableListOf(4, 5) // ❌
var にすれば add できるわけではない
var list = listOf(1, 2)
list.add(3) // ❌
- 型が
Listのままならaddは使えません - 重要なのは
var/valではなく型
実務で推奨される設計パターン
内部は MutableList、外部は List
class Sample {
private val _items = mutableListOf<String>()
val items: List<String> get() = _items
fun addItem(item: String) {
_items.add(item)
}
}
メリット
- 外部から勝手に変更されない
- 変更点を制御できる
- Kotlinらしい安全設計
buildList を使ったモダンな書き方
val list = buildList {
add(1)
add(2)
addAll(listOf(3, 4))
}
- 構築中はミュータブル
- 完成後は
Listとして返る - 安全性と可読性が高い
まとめ
- 要素を追加したい →
MutableList - 外部公開用 →
List - Listに追加したい →
+で新しいListを作る - 大量追加 → MutableList or buildList
- 走査中に構造変更しない
以上、KotlinのListに要素を追加する方法についてでした。
最後までお読みいただき、ありがとうございました。










