Kotlinのリストについて

採用はこちら

KotlinにおけるListは、コレクションの中でも最も頻繁に使われる基本要素です。

しかし一方で、「Listは不変なのか?」「MutableListとの違いは?」といった点で誤解されやすいテーマでもあります。

この記事では、

  • KotlinのListの正確な位置づけ
  • 読み取り専用と変更可能の違い
  • Kotlinらしい安全な使い方
  • 実務での注意点

を順序立てて、仕様に忠実かつ実践的に解説します。

目次

KotlinのListとは

KotlinのListは、順序を持つ要素の集合を表すコレクションです。

主な特徴は次の通りです。

  • 要素には インデックス(0始まり) が割り当てられる
  • 同じ値を複数回保持できる
  • Kotlinでは 「読み取り専用」と「変更可能」 が型として明確に分かれている

この「読み取り専用」という概念が、Java経験者にとって最も重要な違いになります。

ListとMutableListの決定的な違い

Kotlinには、用途の異なる2種類のListがあります。

読み取り専用List(List

val fruits = listOf("Apple", "Banana", "Orange")

特徴

  • この参照からは 追加・削除・更新ができない
  • addremove といった操作は コンパイル時に禁止される
  • 安全な参照用インターフェース

重要なのは、List「不変(immutable)」ではなく「読み取り専用(read-only)」 である点です。

つまり、

  • この変数を通じては変更できない
  • しかし、元のデータが別の参照から変更される可能性はある

という位置づけになります。

読み取り専用 = 絶対に変わらない、ではない

val mutable = mutableListOf(1, 2, 3)
val readOnly: List<Int> = mutable

mutable.add(4)
println(readOnly) // [1, 2, 3, 4]

readOnlyList 型ですが、中身は変化しています。

これはKotlinのListが 「操作制限されたビュー」 であるためです。

変更可能なList(MutableList

val mutableFruits = mutableListOf("Apple", "Banana")

特徴

  • 要素の追加・削除・更新が可能
  • 状態が変化する処理向き
  • UI状態管理や編集処理で使用される

使い分けの指針(実務的)

利用シーン推奨型
参照専用List
内部で要素を変更MutableList
関数の引数原則 List
外部APIとして公開List
状態を持つ処理MutableList

「変更が必要になるまでMutableListを使わない」これがKotlinらしい設計です。

Listの基本操作

要素の取得

val fruits = listOf("Apple", "Banana", "Orange")

fruits[0]      // Apple
fruits.get(1)  // Banana

インデックスが範囲外の場合は IndexOutOfBoundsException が発生します。

サイズ取得

fruits.size

要素の存在確認

"Apple" in fruits
fruits.contains("Pear")

MutableListの操作

要素の追加

val list = mutableListOf("A", "B")

list.add("C")
list.add(1, "X")

要素の削除

list.remove("B")
list.removeAt(0)

要素の更新

list[0] = "Z"

KotlinらしいList操作(高階関数)

KotlinのList操作は、高階関数を使うことで非常に簡潔かつ安全になります。

map(変換)

val numbers = listOf(1, 2, 3)

val doubled = numbers.map { it * 2 }
// [2, 4, 6]
  • 元のListは変更されない
  • 新しいListが生成される

filter / filterNot(抽出)

val even = numbers.filter { it % 2 == 0 }
// [2]

val withoutTwo = numbers.filterNot { it == 2 }
// [1, 3]

find / firstOrNull

numbers.find { it > 1 }       // 2
numbers.firstOrNull()         // 1

findfirstOrNull { 条件 } とほぼ同義です。

any / all

numbers.any { it > 2 } // true
numbers.all { it > 0 } // true

Listの生成方法いろいろ

空のList

val empty = emptyList<String>()

サイズ指定生成

val list = List(5) { it * 2 }
// [0, 2, 4, 6, 8]

生成されるのは 読み取り専用のList です。

配列からListへ変換

val array = arrayOf(1, 2, 3)
val list = array.toList()

Listとnullの扱い(Kotlin特有)

要素がnullを許容するList

val list: List<String?> = listOf("A", null, "B")

List自体がnull

val list: List<String>? = null

この2つは意味がまったく異なります。

「Listがnullなのか」「要素がnullなのか」 を常に意識することが重要です。

ListとSequenceの違い

numbers
    .asSequence()
    .filter { it > 1 }
    .map { it * 2 }
    .toList()
種類特徴
List即時評価・中間Listが生成される
Sequence遅延評価・必要な分だけ処理

※ 小規模データではSequenceが遅くなる場合もあるため、「大量データや複雑なパイプライン処理向け」 と理解するのが適切です。

実務でよくある注意点

MutableListを外部に公開しない

非推奨

fun getItems(): MutableList<String>

推奨

fun getItems(): List<String>

内部ではMutableListでも、外部にはListとして公開するのが安全です。

ループ中の削除に注意

for (item in list) {
    list.remove(item) // 例外の原因
}

安全な代替案

再生成する方法(推奨)

val newList = list.filterNot { it == "A" }

MutableListとして必要な場合

val newList = list.filterNot { it == "A" }.toMutableList()

まとめ

  • KotlinのList読み取り専用インターフェース
  • 「不変」と「読み取り専用」は別概念
  • 変更が必要な場合のみ MutableList を使う
  • 高階関数を使うことで安全かつ簡潔に書ける
  • 外部公開は常に List を基本とする

以上、Kotlinのリストについてでした。

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

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