var を一言でいうと
var は「型を書かなくても、右辺からコンパイラが型を推論してくれるローカル変数宣言」のためのキーワードです。
「型がなくなる」のではなく、「型を書く手間を省く」だけで、コンパイル時の静的型チェックはこれまで通り行われます。
var message = "hello"; // String と推論される
var number = 10; // int と推論される
Javavar を使っても Java は“静的型付き言語”のままです。
「型を省略しても、コンパイラはちゃんと型を知っている」というのが、まず一番大事なポイントです。
var が使える場所・使えない場所
ローカル変数にだけ使える
var が使えるのは「ローカル変数」だけです。
メソッドの中で宣言する変数や、for 文のカウンタなどが対象です。
void sample() {
var text = "hello"; // OK
var list = List.of(1,2); // OK
}
Javaフィールド、メソッド引数、戻り値の型には使えません。
class NG {
// var name; // コンパイルエラー(フィールドには使えない)
// void hello(var msg) {} // コンパイルエラー(引数には使えない)
}
Java「メソッドの外側の“型の顔”はちゃんと書く。
中の細かいローカル変数だけ、var で省略してよい」という設計になっています。
必ず「初期化」とセットで書く必要がある
var は右辺から型を推論するので、初期化なしでは使えません。
// var x; // コンパイルエラー(右辺がないので型が分からない)
var x = 10; // OK(int と推論される)
Javaまた、右辺が null だけでもダメです。
// var value = null; // コンパイルエラー(null だけでは型が決められない)
Java「右辺に“具体的な型を持つ式”があること」が必須条件です。
var の型はどう決まるのか
右辺の“静的型”がそのまま入る
例えば、次のようなコードを見てみます。
var list = List.of("A", "B", "C");
Javaこのとき、コンパイラは list の型を List<String> と推論します。var は「なんとなくの型」ではなく、「本来ここに書くはずだった正確な型」をそのまま当てはめます。
だから、次のようなことも普通に起きます。
var num = 1; // int
num = 2; // OK
// num = "hello"; // コンパイルエラー(String は代入できない)
Javavar を使っても、「型がゆるくなる」「なんでも入る」ことは一切ありません。
“型名を省略しているだけ”だと理解してください。
型推論が「読みにくさ」を生むケース
例えば、これはどうでしょう。
var result = someMethod();
JavasomeMethod() の戻り値の型がコードからすぐに分かるなら問題ありませんが、
ジェネリクスが絡んでいたり、メソッド名が曖昧だったりすると、result の型がパッと見で分かりにくくなります。
var を使うときは、
「右辺を見れば型が一目で分かるか?」
「変数名から“何者か”が想像できるか?」
を自分に問いかけるのが大事です。
var が「特に効く」場面
ジェネリクスで型が長くなるとき
典型的なのは、ジェネリクスで型がやたら長くなるケースです。
Map<String, List<Integer>> map = new HashMap<>();
Javaこれを var で書くと、こうなります。
var map = new HashMap<String, List<Integer>>();
Java右辺に型引数を書いているので、コンパイラは map の型を HashMap<String, List<Integer>> と推論します。
さらに、ダイヤモンド演算子を使えば、もっとスッキリします。
var map = new HashMap<String, List<Integer>>(); // でもいいし
var map2 = new HashMap<String, List<Integer>>(); // でもいい
Java実務では、右辺にファクトリメソッドを使うことも多いです。
var list = List.of("A", "B", "C"); // List<String>
Java「右辺を見れば型が分かる」パターンでは、var はかなり読みやすさに貢献します。
for 文のカウンタや拡張 for
for 文でもよく使われます。
for (var i = 0; i < 10; i++) {
System.out.println(i);
}
for (var s : List.of("A", "B", "C")) {
System.out.println(s);
}
Javaここでは、i は int、s は String と推論されます。
特に拡張 for では、右辺のコレクションの型から要素型が分かるので、var との相性が良いです。
var を「使ってはいけない」わけではないが、乱用は危険
読みやすさを壊す var の例
例えば、こんなコードはどうでしょう。
var x = process(data);
var y = transform(x);
var z = handle(y);
Javaコンパイラ的には何の問題もありませんが、読む人からすると「x / y / z が何の型か」が全く分かりません。var 自体が悪いのではなく、「変数名と右辺から型が想像できない」のが問題です。
もう少しマシにするなら、こうです。
var processedData = process(data);
var transformed = transform(processedData);
var handled = handle(transformed);
Javaそれでも、「どんな型か」はメソッド定義を見に行かないと分かりません。
「ここは型を明示した方が安心だな」と感じたら、素直に型名を書いた方がいいです。
Result result = handle(transform(process(data)));
Java「型を隠す」のではなく「ノイズを減らす」ために使う
var の目的は「型を隠す」ことではなく、「型が明らかな場面で、重複した記述を減らす」ことです。
例えば、こういうのはノイズが多いです。
List<String> names = List.of("Alice", "Bob");
Java右辺を見れば List<String> だと分かるので、ここは var で十分です。
var names = List.of("Alice", "Bob");
Java逆に、右辺だけでは型が分かりにくいときは、var を我慢して型を書いた方が、未来の自分が楽になります。
var と「型安全性」の関係
Java の型安全性は変わらない
もう一度強調しておきますが、var を使っても Java の型安全性は一切変わりません。
var list = new ArrayList<String>();
list.add("hello");
// list.add(123); // コンパイルエラー
Javaコンパイラは list の型を ArrayList<String> と認識しているので、Integer を入れようとすると普通に怒られます。var は「型を省略するための構文糖衣」であって、「動的型付け」ではありません。
キャストや raw 型と組み合わせるときは特に注意
例えば、raw 型を使ってしまうと、var の推論結果も raw 型になります。
List raw = getRawList(); // raw 型
var list = raw; // List と推論される(型引数なし)
Javaここから先は、list に何でも入ってしまう危険な世界です。var を使う前に、「右辺の型がちゃんとジェネリクスで型安全になっているか?」を意識する必要があります。
まとめ:var を自分の言葉でどう使い分けるか
あなたの言葉で var を整理すると、こうなります。
「var は、ローカル変数の“型名を書く手間”を省くためのキーワードで、
右辺からコンパイラが正確な型を推論してくれる。
Java の静的型付けはそのままで、型安全性は一切失われない。
ただし、
・ローカル変数にしか使えない
・必ず初期化とセットで書く必要がある
・右辺や変数名から型が一目で分かる場面で使うべきで、
型が分かりにくくなるなら素直に型名を書いた方が読みやすい。
“型を隠す道具”ではなく、“型が明らかなところでノイズを減らす道具”として使うのがちょうどいい。」

