Javaでは従来、変数宣言時に「int」「String」「List<String>」といった具体的なデータ型を明示的に記述してきました。しかしJava 10で登場した「var」を使うと、変数の型推論(type inference)が行われ、他の言語(JavaScriptやKotlinなど)で見られる「型を省略した変数宣言」のように書くことができます。
このページではJava初心者の方に向けて「var」を利用した変数宣言を理解するためのポイントを順を追って紹介します。
1. varとはなにか
var message = "Hello World"; // コンパイラが自動で String 型だと判断 var number = 10; // コンパイラが自動で int 型だと判断

Javaはコンパイルしたバイトコードを実行する流れですが、このバイトコードを生成する段階で型が一意に決まります。その意味で実行時に動的に型付けがされるJavaScriptのような言語とは仕組みとして異なります。
2. varが使える範囲
「var」はローカル変数としてしか利用できないという特徴があります。実践に即して具体例を挙げると↓のような位置で使用できます。
public void exampleMethod() { var count = 0; var name = "Alice"; ... }
// for文 for (var i = 0; i < 10; i++) { System.out.println(i); } // 拡張for文 var names = List.of("Alice", "Bob", "Carol"); for (var n : names) { System.out.println(n); }
使えない場所としては以下が代表的です。
- メソッドの引数・戻り値の型
- フィールド(クラスメンバ変数)の型
- インスタンス変数やstatic変数の型

「var」はあくまでメソッド内部やブロック内部でしか使えない、と覚えておきましょう。
3. varで宣言するメリット
- 型宣言の簡略化
例として、Genericsを伴うコレクションを宣言する場合、従来は長い記述が必要でした。
List<Map<String, Integer>> list = new ArrayList<>();
これが「var」を使うとちょっとだけすっきりします。
var list = new ArrayList<Map<String, Integer>>();
コンストラクタ右辺の「Map<String, Integer>」情報から、コンパイラはList<Map<String, Integer>>型だと推論します。
4. varのデメリット・注意点
- 可読性が落ちるケースがある
一見、型が推論されるためスッキリするようでいて、逆に「実際にどんな型なのかが分かりにくい」ことがあります。特に右辺のメソッドが複雑なジェネリクス型を返す場合は、エディタの補完やドキュメントを見ないと確信が持てないこともあるでしょう。 - 暗黙の型変換は行われない
「var」はコンパイラが右辺をもとに厳密に型を推論します。例えば、var x = 10;
の時点でx
はint型となり、その後x = 10.5;
のようにdoubleを代入することはできません。 - nullだけを代入する宣言はできない
var test = null;
という形では型が決められません(コンパイルエラー)。必ず具体的なオブジェクトやリテラルを右辺に書く必要があります。 - 初期化子(右辺)が必須
「var」で変数を宣言する際は、必ず同じ行で初期化する必要があります。これはコンパイラが型推論をするために必須の手順です。
var s; // コンパイルエラー:初期値がない s = "Hello";
5. 実践でよくある使いどころ
- ストリームAPIの途中の変数受け取り
var result = list.stream() .filter(...) .map(...) .collect(Collectors.toList());
6. 推論される型を確認する方法
6-1. IDEの補助機能を使う
6-2. コンパイラのエラーを活用する
6-3. ツールや静的解析を利用する
7. ラムダ式での「var」の利用
7-1. ラムダ式のパラメータにvarを使う(Java 11~)
// Java 11 以降 (var s) -> s.toUpperCase()
(var @NonNull s) -> s.toUpperCase()
7-2. ラムダ式内部でのローカル変数にvarを使う
var list = Arrays.asList("Apple", "Banana", "Cherry"); list.forEach(item -> { var upper = item.toUpperCase(); System.out.println(upper); });
8. 匿名クラス・インナークラスとの違い
var thread = new Thread(new Runnable() { @Override public void run() { // ここでのvarは通常通り使える var localVar = "test"; System.out.println(localVar); } });
9. try-with-resources構文とvar
try (var br = new BufferedReader(new FileReader("test.txt"))) { // br は自動的にCloseableとして扱われる System.out.println(br.readLine()); } catch (IOException e) { e.printStackTrace(); }
10. 大規模開発における「var」導入のベストプラクティス
- チームでルールを決める
- 例えば「基本的には型を書き、ジェネリクスが煩雑な場合に限りvarを使う」「テストコードでは自由に使ってよい」など、ガイドラインを作ることで、コードベースが「varだらけ」になって混乱するのを防ぎます。
- 変数名をわかりやすくする
- 「var」を使う場合、変数名が型のヒントとなるようにするのが望ましいです。
- 変数名やメソッド名が「何を返すのか」分かりやすくすることで、IDEがなくてもコードリーディングが可能になります。
- 必要以上にvarを使わない
- 「型が簡潔に書ける場所」や「変数の型が明らかである場所」に限定して使うことで、可読性を損なわずに恩恵だけ享受できます。
- たとえば、単純な
int
やString
のように明らかに分かりやすい型では、わざわざ「var」を使わないケースが多いです。
- 型が複雑すぎるならメソッド分割も検討
- 「varのおかげでスッキリ書けているけれど、右辺のメソッド呼び出しが極端に長い・複雑」という場合、メソッドを分割して可読性を上げることも検討します。
- すなわち「varを使う」はあくまで一手段であって、根本的には読みやすいメソッド設計が必要です。
11. 具体的な利用例(まとめ)
ここまでの内容を踏まえ、以下のようなサンプルを通して「var」の使い方を再度整理しましょう。
public class VarSample { public static void main(String[] args) { // 1. 文字列 (String) var greeting = "Hello, var!"; System.out.println(greeting); // greetingはString型と推論 // 2. 数値 (int) var count = 10; // count = 10.5; // コンパイルエラー:countはint型 // 3. 複雑なジェネリクス var userMap = new HashMap<String, List<Integer>>(); userMap.put("Alice", List.of(1,2,3)); userMap.put("Bob", List.of(4,5)); System.out.println(userMap); // 4. ストリームAPI var result = userMap.entrySet().stream() .filter(e -> e.getValue().size() > 2) .map(e -> e.getKey()) .toList(); // resultはList<String>と推論される System.out.println(result); // 5. try-with-resources try (var br = new BufferedReader(new FileReader("example.txt"))) { System.out.println(br.readLine()); } catch (IOException e) { e.printStackTrace(); } // 6. 拡張for文 var list = List.of("Java", "Kotlin", "Scala"); for (var lang : list) { System.out.println(lang); } // 7. ラムダ式(Java 11~ varパラメータ) // (var s) -> s.toLowerCase() list.forEach((var item) -> System.out.println(item.toUpperCase())); } }
このように、実際のコードでも「var」がさまざまなシーンで利用可能であることが分かります。