KotlinのListに要素を追加する方法について

採用はこちら

Kotlinで List に要素を追加しようとして、

  • add() が使えない
  • コンパイルエラーになる
  • Javaと同じ感覚で書けない

と戸惑う人は非常に多くいます。

これは Kotlin の ListJavaとは設計思想そのものが違う ためです。

この記事では、

  • Kotlinの ListMutableList の本当の違い
  • 要素を追加する正しい方法
  • 実務で安全に使える設計パターン

を段階的に解説します。

目次

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() が返す型が List
  • List には 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に要素を追加する方法についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次