仕事でコーディングをしていると、いつもぶち当たる壁、それがnull。
先輩:ここはnull考慮しなきゃいけないよね~、ここではnullチェック入れて~、あ、引数がnullでも大丈夫だからね~
私:…すみません。よくわかりません。(脳内回線ショート)
ということで、今回はnullについて本腰入れて向き合ってみたいと思います!!
nullってなんなの?…の前に。
nullについて語る前に、前提となる知識があります。
プリミティブ型と参照型です。
Javaの型は大きく上記2つに分かれます。
プリミティブ型
プリミティブ型は以下の8つです。
| 型名 | 説明(ざっくり) |
|---|---|
| byte | 範囲せませまな整数値 |
| short | byteとshortの間の整数値 |
| int | とりあえずこれ使っとけ!な整数値 |
| long | intより範囲広い整数値 |
| float | 小数も使えるようになったよ |
| double | さらにたくさんの小数も使えるようにしといたよ |
| boolean | true or false |
プリミティブ型の最大の特徴は、変数そのものが値をもつ、ということです。
たとえば
int num = 100;
と宣言したとき。
パソコンのメモリのX番地に、「100」という値がポンと放り込まれます。
で、numを使うときはそのポンと放り込まれた100という数値を参照するわけです。
そして、次に
int num2 = num;
としたとき。
num2に対応するメモリのY番地に、また「100」という値がポンと放り込まれます。
numのX番地に入っている100の値をコピーして新たにY番地に格納する感じです。
numとnum2は同じ値ですが独立して存在します。
では、参照型は?
参照型はプリミティブ型以外のすべての型と思ってもらってよいです。オブジェクトです。
例えば以下のようにString型の変数を宣言したとします。
String str = "こんにちは"
すると、パソコンの内部では"こんにちは"がメモリ内のX番地にポン、そしてX番地の位置情報がY番地にポンされます。strを使うときは、"こんにちは"が格納されているX番地ではなく、Y番地を経由してX番地にたどり着く感じです。
次に、
String str2 = str
とすると、str2に対応するZ番地にX番地の位置情報がポンされます。
ここでようやくnullの話に。
結論から言うと、nullはこの「位置情報」が「ない」状態です。
正確に言うと、位置情報がどこも指し示していない感じ。
ないものは使えないからnullです。
ゆえに、参照型しかnullを扱えません。
プリミティブ型は「位置情報」という概念がないからです。
nullだとまずいケースは?
nullだとまずいケース、すなわち「ぬるぽ(NullPointerException)」が出るのはどんなケースなのでしょうか?
結論:nullになっている変数にアクセスしようとしたとき。
例)null.XXX()みたいに、nullになっている変数のメソッドを呼び出そうとした。
なので、例えばメソッドの引数で渡ってきた値がnullだったとか、それだけならエラーにはなりません。その中のメソッドでぬるぽになる可能性はありますが。
ぬるぽを回避・ハンドリングするには?
- 処理の前にnullチェックを入れる
- ぬるぽをcatchして例外ハンドリングしてあげる
など。
閑話休題: classX obj; と classX obj = null; は何が違うのか?
要は初期化をどうするかという話です。
ここまで読まれた方はなんとなくわかると思いますが、結論、
classX obj => メモリにobj用の領域を用意しただけ
classX obj = null => メモリにobj用の領域を用意し、明示的に位置情報: nullを入れてあげる
です!
なので、class X obj; とだけ書いていて、そのobjを使おうとすると下記のように怒られます。

The local variable str1 may not have been initialized
= この変数は初期化されてないと思いますよ ですね。
ここで classX obj = nullとしてあげればエラーは解消します。
コンパイルエラーでぬるぽが起こるかもしれませんが。
上記エラーが出るのはローカル変数の場合です。
フィールド(メンバ変数)の場合は classX obj; と書いただけで自動でnullが入るので心配ご無用。
おまけ: スタック領域とヒープ領域
前項でプリミティブ型と参照型について書きましたが、そこにちょっと絡んでくる話です。
コンピュータのメモリには
- スタック領域
- ヒープ領域
があります。
ざっくり、
| 領域名 | 特徴 |
|---|---|
| スタック領域 | 積み上げ式の記憶領域。OSがソフトウェアに割り当てる。サイズに制限あり。 |
| ヒープ領域 | 仮の作業場。動的に領域の確保・解放ができる(Javaだとガベージコレクション) |
という感じ。
スタック領域は高速な割に融通が利かない感じ、ヒープ領域は低速な代わりに柔軟性がある感じです。
プリミティブ型と参照型の値はそれぞれうまく使い分けて保存されるみたいです。
これ以上はちょっと理解が追い付かなかったのでここでは割愛します。
興味がある人は調べてみてください🔍
以上です! ではでは。