TL;DR
オブジェクトやデータが、作成した後に状態を変更できないこと。対義語はミュータブル(変更可能)である。
なぜ必要か
状態が変わらないので、他のスレッドによる変更を心配せずにデータを読める。排他制御がいらず、スレッドセーフになる。複製も参照のコピーで済むので、メモリを節約でき、複製や比較の処理を省ける。
Domain Modeling Made Functional によると、値オブジェクトはイミュータブルであることが求められる。一方、エンティティは時間とともに変化するので、アイデンティティを持つ。
仕組み
値を変えたいときは、元のデータを書き換えずに、変更を反映した新しいデータを作る。関数型プログラミングでは値がデフォルトでイミュータブルなので、変更はコピーを作ることで表す。
例
Java の String はイミュータブルである。toLowerCase() は元の文字列を書き換えず、新しい String を返す。変数の値を更新するには、戻り値を代入し直す。
注意点
イミュータブルは、メモリ上で書き込めないという意味ではなく、主にプログラマが守る設計上の約束である。たとえば、コンストラクタで受け取ったリストの参照をそのまま保持して返すクラスは、外からリストの中身を書き換えられるのでイミュータブルではない。リストを複製して読み取り専用のビューを返しても、要素自体が変更可能なら完全にはイミュータブルにならない。
変更可能な内容を多く持つデータでは、イミュータブルにするのが不適切なことも多い。そのため多くの言語では、イミュータブルとミュータブルを選べるようになっている。