var(ローカル変数型推論)(Java)
Java 10 で追加された、ローカル変数の型をコンパイラに推論させるキーワードです。『Java』では変数を宣言するときに型名を明示するのが基本ですが、var を使うと右辺の値からコンパイラが型を自動判定してくれるため、冗長な型名の繰り返しを省略できます。ただし使える場所は限られており、フィールド・メソッド引数・戻り値型には使用できません。可読性のトレードオフと適切な使いどころも合わせて解説します。
構文
// 型名の代わりに var を書くと、右辺からコンパイラが型を推論します var 変数名 = 初期値; // 具体例です var name = "孫悟空"; // String と推論されます var power = 9000; // int と推論されます var isHero = true; // boolean と推論されます var fighter = new Saiyan(); // Saiyan と推論されます
var が使える場所・使えない場所
| 場所 | var の使用 | 理由 |
|---|---|---|
| ローカル変数(メソッド内) | 使用できます。 | 右辺の初期値からコンパイラが型を推論できます。 |
拡張 for 文のループ変数 | 使用できます。 | コレクション・配列の要素型から推論されます。 |
try-with-resources の変数 | 使用できます。 | 右辺のリソース型から推論されます。 |
| クラスフィールド(インスタンス変数・クラス変数) | 使用できません。 | 初期化子がなかったり、後から代入されたりする可能性があるため型が確定できません。 |
| メソッドの引数 | 使用できません。 | 呼び出し側がどの型で渡すかが呼び出し時までわからないため推論できません。 |
| メソッドの戻り値型 | 使用できません。 | 呼び出し元がシグネチャで型を確認できなくなるため禁止されています。 |
初期値なしの宣言(var x;) | 使用できません。 | 推論の根拠となる初期値がないため型が確定できません。 |
null だけを代入(var x = null;) | 使用できません。 | null からは型を推論できません。 |
サンプルコード
VarBasic.java
import java.util.ArrayList;
public class VarBasic {
public static void main(String[] args) {
// --- プリミティブ型のラッパーや String への var 使用 ---
var heroName = "孫悟空"; // String と推論されます
var power = 9000; // int と推論されます
var isSuper = true; // boolean と推論されます
var ratio = 1.5; // double と推論されます
System.out.println(heroName + " 戦闘力: " + power);
System.out.println("スーパーサイヤ人か: " + isSuper);
System.out.println("倍率: " + ratio);
// --- オブジェクト型への var 使用 ---
// new の右辺に型名が書いてあるため、左辺の var は冗長な繰り返しを省けます
var fighters = new ArrayList<String>();
fighters.add("孫悟空");
fighters.add("ベジータ");
fighters.add("ピッコロ");
fighters.add("クリリン");
System.out.println("参戦ファイター: " + fighters);
// --- 拡張for文のループ変数への var 使用 ---
// コレクションの要素型(String)から推論されます
for (var name : fighters) {
System.out.println("・" + name);
}
}
}
javac VarBasic.java java VarBasic 孫悟空 戦闘力: 9000 スーパーサイヤ人か: true 倍率: 1.5 参戦ファイター: [孫悟空, ベジータ, ピッコロ, クリリン] ・孫悟空 ・ベジータ ・ピッコロ ・クリリン
VarReadability.java
import java.util.HashMap;
import java.util.Map;
public class VarReadability {
public static void main(String[] args) {
// --- var が可読性を高める例 ---
// 型名が長いときに左辺の繰り返しを省けます
// 型名あり(型名が2回書かれていて冗長です)
HashMap<String, Integer> powerMapTyped = new HashMap<String, Integer>();
// var あり(右辺を見れば型は一目瞭然です)
var powerMap = new HashMap<String, Integer>();
powerMap.put("孫悟空", 150000000);
powerMap.put("ベジータ", 120000000);
powerMap.put("フリーザ", 120000000);
powerMap.put("セル", 900000000);
powerMap.put("魔人ブウ", 999999999);
// Map.entrySet() のイテレーションでも var が有効です
// Map.Entry<String, Integer> という長い型名を省略できます
System.out.println("=== 戦闘力ランキング ===");
for (var entry : powerMap.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
// --- var が可読性を下げる例 ---
// 右辺を見ても型がすぐにわからない場合は var を避けるべきです
var result = getPowerLevel(); // getPowerLevel() の戻り値型を知らないと型が不明です
System.out.println("戦闘力スキャン結果: " + result);
}
// 戻り値型は var では書けません(コンパイルエラー)。必ず型名を明示します
static int getPowerLevel() {
return 530000;
}
}
javac VarReadability.java java VarReadability === 戦闘力ランキング === 孫悟空 : 150000000 ベジータ : 120000000 フリーザ : 120000000 セル : 900000000 魔人ブウ : 999999999 戦闘力スキャン結果: 530000
VarRestrictions.java
public class VarRestrictions {
// --- フィールドには var は使えません ---
// var raceName = "サイヤ人"; // コンパイルエラー:フィールドに var は使用できません
String raceName = "サイヤ人"; // フィールドは型名を明示します
public static void main(String[] args) {
// --- 初期値なしには var は使えません ---
// var hero; // コンパイルエラー:初期値がないと型を推論できません
// var villain = null; // コンパイルエラー:null からは型を推論できません
// --- 正しい使い方: 初期値ありのローカル変数 ---
var heroName = "孫悟空"; // OK: String と推論されます
var enemyName = "フリーザ"; // OK: String と推論されます
// var は宣言後に別の型の値を代入することはできません
// 推論された型(String)以外を代入しようとするとコンパイルエラーになります
// heroName = 9000; // コンパイルエラー:String 型の変数に int は代入できません
System.out.println("主人公: " + heroName);
System.out.println("敵役: " + enemyName);
// --- 引数には var は使えません ---
// 引数の型は明示する必要があります
printStatus(heroName, 150000000); // 呼び出し側は普通に渡せます
}
// メソッドの引数・戻り値型には var は使えません。型名を明示します
static void printStatus(String name, int power) {
System.out.println(name + " の戦闘力: " + power);
}
}
javac VarRestrictions.java java VarRestrictions 主人公: 孫悟空 敵役: フリーザ 孫悟空 の戦闘力: 150000000
var を使うべき場面・避けるべき場面
| 場面 | 推奨 | 理由 |
|---|---|---|
new HashMap<String, Integer>() など型名が長いとき | var を使う | 右辺に型が明示されているため可読性が損なわれません。 |
Map.Entry<K, V> など拡張 for 文のループ変数 | var を使う | 型名が長く冗長になりがちな箇所をシンプルにできます。 |
| メソッド戻り値を受け取るとき(型名が自明でない場合) | 型名を明示する | var だと型が不明瞭になり、コードを読む人が混乱する場合があります。 |
int・boolean など型名が短いとき | どちらでも可 | 省略しても冗長さは少ないため、チームの規約に従います。 |
| フィールド・引数・戻り値型 | 使用不可 | 言語仕様として禁止されています。 |
概要
var はローカル変数専用の型推論キーワードです。var はあくまでコンパイル時に型が確定する静的型付けであり、型がなくなるわけではありません。推論された型以外の値を後から代入しようとすればコンパイルエラーになります。JavaScript の var(動的型付け)とは全く異なる概念です。
var を使う最大のメリットは、new HashMap<String, List<Integer>>() のように型名が長い場合に左辺の繰り返しを省いてコードをすっきりさせることです。一方で、メソッドの戻り値を受け取る変数など「右辺を見ても型がすぐにわからない箇所」で var を使うと、コードを読む人が型を追うコストが増えます。
フィールド・メソッド引数・戻り値型には var は使用できません。また var で宣言する際には必ず初期値が必要であり、null だけを初期値にすることもできません。使える場所はローカル変数・拡張 for 文のループ変数・try-with-resources の変数の3つと覚えておくと迷いません。
ローカル変数の型宣言については『プリミティブ型』を、final キーワードとの組み合わせ(final var)については『final キーワード』を、try-with-resources での利用については『try-with-resources』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。