null の問題
ポインターを利用するプログラミング言語での NULL ポインターや、参照型データでの null
の取り扱いには多くの問題があります。
歴史的にも多くのプロジェクトで問題を引き起こしており、多くのソフトウェアエンジニアが苦労している問題でもあります。
そのため、null
を安全に取り扱うための手法が多く存在します。
ここでは null
によって引き起こされる問題を紹介します。
実体が存在しないためオブジェクトとしては利用できない
参照型の変数に null
が代入されている場合には実体が存在しないため変数経由でメンバーにアクセスすることができません。
// null 例外の出るコード
List<int> numbers = null;
// この行を実行すると NullReferenceException 例外が発生します
Console.WriteLine("numbers.Count: {0}", numbers.Count);
この C# で記述されたコードでは変数 numbers
のメンバーへのアクセスを行うと NullReferenceException
が発生します。
参照型の変数に null
が代入されている場合には null
以外の値が代入されているときの挙動と異なり、例外が発生することになります。
見方によっては変数に null
が代入されている場合には本来の変数の型の挙動を満たしてない様にも見えます。
null
の代入された変数に対してアクセスしようとすると NullReferenceException
が発生し、最悪の場合プログラムが終了することになります。
null でないことは動的にしか確認できないプログラミング言語が多い
null
を安全に取り扱うための文法機能や標準ライブラリを持っていないプログラミング言語では静的に (コンパイル時に) 利用する変数が null
なのかどうかをチェックすることができません。
そのため、実行時に null
でないことを確認する必要があります。
また、動的にしかチェックできないため、今この変数は null
チェックがされた後なのか、される前なのかが機械的には分からず、全ての個所でプログラマーが気を付ける必要があります。
場合によっては null
チェックされておらずに NullPointerException
を出してしまったり、逆に必要以上の null
チェックをしてしまう場合があります。
List<int> numbers = null;
if (numbers == null)
{
// numbers が null だった場合の処理
}
// ここで numbers が null でないことはプログラマーが直前のソースコードを読んで確認するしかありません
// 例えば、上の if 文の中で numbers へのデフォルト値の代入や retrun などの処理が行われていなかった場合には、この箇所で numbers が null である可能性があります
コードによっては静的解析ツールの助けを借りることによって、事前に検出することも可能です。
List<int> numbers = null;
Console.WriteLine("numbers.Count: {0}", numbers.Count);
この例の様に null
を代入した直後にメンバーにアクセスするような場合には、静的解析ツールによって問題を検出することができる場合がありますが、複雑な処理の結果 null
が代入されている場合には検出することは困難です。
対処方法
null
の取り扱いに関しては昔から問題になっているため以下の様に多くの解決策が存在します。
- null object
- Maybe モナド, Option
- null 安全