Kotlinは2種類のコレクションを提供しています:不変(immutable)と可変(mutable)。
List — 不変リスト。要素を追加または削除することはできません。MutableList — 可変リスト:要素を追加したり削除したりできます。Set — 不変集合(ユニークな要素)。MutableSet — 可変集合。Map — 連想配列(キー-バリュー)、不変。MutableMap — 可変連想配列。val fruits: List<String> = listOf("Apple", "Banana", "Cherry") val mutableFruits: MutableList<String> = mutableListOf("Apple", "Banana") mutableFruits.add("Cherry") val fruitSet: Set<String> = setOf("Apple", "Banana") // 要素のユニーク性 val mutableFruitSet: MutableSet<String> = mutableSetOf("Apple", "Banana") mutableFruitSet.add("Cherry") val scores: Map<String, Int> = mapOf("Tom" to 80, "Jane" to 90) val mutableScores: MutableMap<String, Int> = mutableMapOf("Tom" to 80) mutableScores["Jane"] = 90
注意点:
Listを返します(MutableListではありません)。
List<T>をパラメータとして受け取る関数がある場合、その関数の内部でこのリストを変更することはできますか?
回答: いいえ、List<T>型のパラメータの場合、関数の内部で要素を追加または削除することはできません。しかし、実際にMutableList<T>が渡された場合、それをこの型にキャストすることが可能です(リスクを引き起こします):
fun modifyList(list: List<String>) { if (list is MutableList) { list.add("Another") // 元のコレクションが可変の場合は動作します } }
このようなことは推奨されません、契約が破られるからです(Listは不変であるべきです!)。
逸話
大規模プロジェクトで
List<Customer>を受け取る関数を使用し、内部で新しい要素を追加しようとしました。コンパイルエラー(add/clear/removeがListに対して定義されていない)がレビュー時に発見されました。データを変換するために可変リストが必要だったからです。
逸話
コレクションが
MutableListとして宣言されていましたが、同期なしで複数のスレッドに渡されました。結果として競合する変更が発生し、 "ConcurrentModificationException"が発生し、リストの状態が壊れました。エラーは長い間探され、スレッドセーフが考慮されませんでした。
逸話
あるサービスでデータベースからの結果を操作するために
mutableListOfを使用し、その後外部にリンクを渡しました。外部のコードが誤ってリストをクリアしてしまいました。その結果、ユーザーには空のデータが届きました。リンクがクローンされず、mutableコレクションがビジネスロジックの層の外で変更されたからです。