変数とは
変数とは、値を保持する名前付きの箱です。Javaではすべての変数に固定の型があり — 宣言時に決まります — その型は決して変わりません。これこそがJavaを静的型付けたらしめているものです。コンパイラはプログラムが実行される前にすべての変数の型を把握しており、箱に間違った種類の値を入れるコードはコンパイルを拒否します。
宣言は3つの部分からなります。型、名前、そして(たいていの場合)初期値です。
int age = 30; は「age という名前の int を作り、その中に 30 を入れる」と読みます。セミコロンは文を終わらせます。コメントのページで、すべての文がそうすると示したとおりです。
今は宣言、代入は後で
宣言と最初の代入を分けることができます。型は宣言時に一度だけ書き、その後は名前と = だけで代入します。
初心者がつまずくルールが一つあります。ローカル変数には、読み取る前に必ず値を代入しなければなりません。コンパイラはこれを追跡し、初期化されていないローカル変数を読み取るコードを拒否します。
int score;
System.out.println(score); // compile error: variable score might not have been initialized
これは厄介事ではなく機能です。プログラムが実行される前に、丸ごと一種類のバグを捕まえてくれます。
命名ルールと慣習
Javaはいくつかの厳格なルールを課し、その上に慣習を重ねます。ルールはこうです。名前には英字・数字・_・$ を含められますが、数字で始めることはできず、予約語(int や class など)にもできず、大文字と小文字を区別します(age と Age は別々の変数です)。
誰もが従う慣習はこうです。
- 変数とメソッドは
camelCaseを使います:firstName、totalScore。 - 定数は
UPPER_SNAKE_CASEを使います:MAX_USERS。 - 名前は値を説明するものにします:
cではなくcount、xではなくuserEmail。
分かりやすい名前は飾りではありません。未来の自分がコードを読むための手立てそのものです。totalPrice = itemCount * pricePerItem は、t = c * p には決してできないやり方で、それ自体が説明になっています。
型安全性:箱は自分の型を保ち続ける
型は宣言時に固定されるため、間違った型の値を変数に入れることはできません。これによりミスがコンパイル時に捕まります。
int age = 30;
age = "thirty"; // compile error: incompatible types - String cannot become int
数値型どうしの代入は拡大変換(widening)のルールに従います。小さい型は大きい型へ自動的に流れ込みますが、その逆はできません。これについてはデータ型と型変換のページで詳しく扱います。今のところは、コンパイラが見張っているということだけ覚えておいてください。
varキーワード
Java 10以降、型の代わりに var と書き、右辺の値からコンパイラに型を推論させることができます。
var は動的型付けではありません。name は String name と書いた場合とまったく同じ String であり、後から int を代入することは依然としてできません。タイプ量を減らすだけです。注意点として、var は推論のもとになる初期化子が必要なので var x; は不正であり、ローカル変数でのみ機能します — フィールド・メソッドのパラメータ・戻り値の型では決して使えません。右辺から型が明らかな場合に使い、明示したほうが分かりやすい場合は型を書き下しましょう。
finalによる定数
設定後に決して変わるべきでない値は final を付けます。再代入しようとすると、それはコンパイルエラーになります。
final は意図を伝え(「これは固定値だ」)、コンパイラがあなたの代わりにそれを守ってくれます。値が概念的に定数であるとき — 利率、上限、設定キーなど — は迷わず使いましょう。そうすれば、うっかりした再代入が、静かにバグとしてリリースされる代わりに捕まえられます。
変数のスコープ
変数は、それが宣言されたブロック — { ... } — の中だけに存在し、閉じ波かっこで消滅します。これがそのスコープです。ループや if ブロックの中で宣言された変数は、その外からは見えません。
i も square もループに属し、ループが終わると消えます。total は外側のブロックで宣言されているので生き残ります。実践的な要点はこうです。各変数は、それを必要とする最小のブロックで宣言しましょう。狭いスコープは、注意を奪い合う名前が減り、値が設定された場所から遠く離れたところで誤用される機会も減ることを意味します。
次へ:データ型
このページのすべての変数は型から始まりました — int、double、String、boolean。次のページではJavaのデータ型を詳しく分解します。8つのプリミティブ型、それぞれの大きさ、プリミティブとオブジェクトの違い、そしてどんなときにどの型を選ぶべきかを扱います。
よくある質問
Javaで変数を宣言するにはどうすればよいですか?
まず型を書き、次に名前を書き、必要に応じて値を代入します:int age = 30;。型(int)は変数の生存期間中ずっと固定で、名前(age)はそれを参照する手段です。宣言と後からの代入に分けることもできます — int age; age = 30; — が、ローカル変数を読み取る前には必ず値を代入しておく必要があります。
Javaのvarキーワードとは何ですか?
Java 10以降、var を使うとコンパイラが代入した値からローカル変数の型を推論します:var name = "Ada"; とすると name は String になります。それでも静的型付けのままで、型は実行時ではなくコンパイル時に確定し、動的ではありません。var は初期化子を持つローカル変数でのみ機能し、フィールド・パラメータ・初期化なしの宣言では決して使えません。
Javaで定数を作るにはどうすればよいですか?
final キーワードを付けます:final double PI = 3.14159;。いったん代入された final 変数は再代入できず、コンパイラがあらゆる試みを拒否します。慣例として、定数は通常の変数と区別できるよう UPPER_SNAKE_CASE で書きます。