Javaのvarは、Java 10から使えるローカル変数の型推論機能です。String message = "Hello"; を var message = "Hello"; と書けるようになり、特にジェネリクスなどの長い型宣言がすっきりします。
ただし「何でもvarにすればいい」というわけではありません。使いどころを間違えると、かえってコードが読みにくくなります。
この記事では、varの基本ルール、使える場面と使えない場面、メリット・デメリット、そしてチーム開発でのベストプラクティスまでを、実例コード付きで解説します。Java歴10年以上の筆者が実務で得た知見も交えてお伝えします。
Javaのvarとは?型推論が導入された背景

var は、Java 10から導入された「ローカル変数型推論」のための機能です。変数を宣言する際に、型の代わりに var と記述すると、コンパイラが初期化の値から自動的に型を判断(推論)してくれます。
これは、Javaが動的型付け言語になったわけではありません。あくまでコンパイル時に型が決定される静的型付け言語である点は、今までと全く同じです。コードの記述量を減らし、より現代的なプログラミングスタイルを可能にするために導入されました。
varが使えるようになったバージョン(Java 10)
var は、2018年にリリースされた Java 10 で正式に導入されました。そのため、Java 9以前の環境では使用できません。
長期サポート(LTS)バージョンであるJava 11から本格的に普及しました。2026年現在のLTS最新版であるJava 25でも当然サポートされており、今やvarは多くのプロジェクトで標準的に使われる機能です。これからJavaを学ぶ方は、必ず押さえておきましょう。
型推論(type inference)の仕組み
型推論は、決して難しい仕組みではありません。コンパイラが、代入される値(右辺)を見て、変数の型(左辺)を「賢く推測してくれる」機能です。
例えば、以下のコードを見てみましょう。
// 従来の書き方
String message = "Hello, Java!";
// varを使った書き方
var message = "Hello, Java!";var を使った場合、コンパイラは右辺の "Hello, Java!" が文字列リテラルであることから、変数 message の型を String であると自動的に判断します。プログラマが明示的に String と書かなくても、コンパイル後のコードは全く同じものになるのです。
varとJavaScriptのvarの違いに注意
var というキーワードから、JavaScriptを連想する方もいるかもしれません。しかし、Javaの var とJavaScriptの var は全くの別物なので注意が必要です。
- Javaのvar
- 静的型付けです。一度型が決まったら、あとから別の型の値は代入できません。
- 型推論はコンパイル時に行われます。
var message = "こんにちは"; // messageはString型に確定
message = 123; // コンパイルエラー! String型にintは代入できない- JavaScriptのvar
- 動的型付けです。同じ変数に異なる型の値を再代入できます。
var message = "こんにちは"; // messageはstring型
message = 123; // エラーにならない! messageはnumber型になるJavaとJavaScriptのvarの違いを理解しておかないと、思わぬバグの原因になります。Javaの var は、あくまで型宣言を省略するためのシンタックスシュガー(糖衣構文)であると覚えておきましょう。
Java varの基本的な使い方

ここからはvarの具体的な使い方を見ていきます。ルールはシンプルで、一度覚えればすぐ活用できます。
宣言と初期化のルール
var を使うには、いくつかの重要なルールを守る必要があります。特に以下の3点は必ず押さえてください。
- 宣言と同時に初期化が必須。
varは右辺の値から型を推論するため、宣言するだけでは型が決まらず、コンパイルエラーになります。
var message; // NG! 初期化されていないため型が推論できない
message = "Hello";- null での初期化はできないnull はどの参照型にも代入できる特殊な値です。そのため、null だけでは具体的な型を推論できず、エラーになります。
var user = null; // NG! nullから型は推論できない- ローカル変数にしか使えないvar が使えるのは、メソッド内やforループ内などのローカル変数に限られます。クラスのフィールド(メンバー変数)やメソッドの引数、戻り値の型としては使用できません。
varで使える場面と使えない場面
var はどこでも使えるわけではありません。使える場面と使えない場面を、コード例と共に整理します。
【使える場面】
- ローカル変数の宣言
public void processData() {
var name = "Taro Yamada"; // String型
var age = 25; // int型
var userMap = new HashMap<Integer, String>(); // HashMap<Integer, String>型
}var userList = List.of("Taro", "Hana", "Jiro");
for (var user : userList) {
System.out.println(user.toUpperCase());
}- try-with-resources文
try (var reader = new BufferedReader(new FileReader("file.txt"))) {
// ファイル読み込み処理
} catch (IOException e) {
e.printStackTrace();
}【使えない場面】
- フィールド(インスタンス変数、クラス変数)
public class User {
private var name = "Taro"; // NG! フィールドには使えない
}- メソッドの戻り値
public var getUserName() { // NG! メソッドの戻り値には使えない
return "Taro";
}- メソッドの引数
public void printMessage(var message) { // NG! メソッドの引数には使えない
System.out.println(message);
}- ラムダ式(Java 10まで)Java 10では使えませんでしたが、Java 11以降はvarが使えます(詳細は後述のJEP 323セクション参照)。
配列・ジェネリクスでのvar利用例
var は、特に型名が長くなりがちなジェネリクスや配列で真価を発揮します。コードが非常にすっきりと読みやすくなるのが分かります。
- ジェネリクスでの利用
ArrayListやHashMapのような、ジェネリクスを使った複雑な型宣言がとてもシンプルになります。右辺の型定義は省略できない点に注意してください。
// 従来
Map<String, List<Map<Integer, String>>> complexData = new HashMap<>();
// varを使用
var complexData = new HashMap<String, List<Map<Integer, String>>>(); - 配列での利用配列の宣言も
varで行えます。配列の場合も、右辺でnew int[]のように型を明示する必要があります。
// 従来
int[] numbers = {1, 2, 3, 4, 5};
// varを使用
var numbers = new int[]{1, 2, 3, 4, 5}; varとfinal varの組み合わせ
モダンなJava開発では、再代入しない変数にfinalを付ける習慣が推奨されています。varとfinalを組み合わせることで、型宣言を省略しつつ再代入を防止できます。
// final var: 型推論 + 再代入不可
final var maxRetry = 3;
final var userName = getUserName();
// 再代入しようとするとコンパイルエラー
// maxRetry = 5; // NG! finalなので再代入できない実務ではfinal varを積極的に使うのがおすすめです。変数が変更されないことが保証されるため、コードの安全性と可読性が向上します。
Java 11以降: ラムダ式の引数でvarが使える(JEP 323)
Java 11では、JEP 323によりラムダ式の引数にもvarが使えるようになりました。通常のラムダ式と動作は同じですが、引数にアノテーションを付けたいときに便利です。
// Java 11以降: ラムダ式の引数にvarが使える
// アノテーションを付けたいときに便利
(@Nonnull var x, @Nullable var y) -> x.process(y);
// 通常のラムダと同等(型推論される)
(var x, var y) -> x + y;
// 注意: varと型名の混在は不可
// (var x, int y) -> x + y; // NG! 全引数varか全引数省略のどちらかラムダ引数でvarを使う場合は、全ての引数をvarにするか、全て省略するかの二択です。varと明示的な型名を混在させるとコンパイルエラーになります。
varを使うメリットとデメリット

varは便利な機能ですが、良い面ばかりではありません。メリットとデメリットを正しく理解し、適切に使い分けるのが重要です。
コードが簡潔になるメリット
最大のメリットは、コードの記述量が減り、見た目がすっきりする点にあります。
特に、前述のジェネリクスのように型名が非常に長くなる場合、var を使うことでコードの水平方向のスペースが削減され、変数名やロジックそのものに集中しやすくなります。
// 長いクラス名やジェネリクスで効果絶大
var inputStream = new FileInputStream("data.bin");
var userRankingMap = new TreeMap<Integer, List<User>>();
// メソッドチェーンの結果を受ける場合も見やすい
var filteredUsers = userList.stream()
.filter(u -> u.getAge() >= 20)
.collect(Collectors.toList());冗長な型宣言を省略できるため、コードの可読性が向上し、開発効率もアップします。
可読性が下がるケース
一方で、varの乱用はコードの可読性を著しく低下させる危険性をはらんでいます。
例えば、以下のようなコードはどうでしょうか。
var result = dataProcessor.execute();このコードだけでは、変数resultの型がすぐに分かりません。型を知るにはexecute()メソッドの定義までジャンプしなければなりません。コードを読む人にとって大きな負担になります。
右辺から型が自明でない場合や、ビジネスロジック上、型そのものが重要な意味を持つ場合には、var を使うべきではありません。
チーム開発での注意点
個人開発であれば自分の判断で使えますが、チームで開発を進める上では、var の使い方についてコーディング規約を設けるのが望ましいです。
こうしたルールをチームで共有しておかないと、人によって書き方がバラバラになります。結果として、コードベース全体の可読性やメンテナンス性が下がります。「var を使っても良いが、変数名で型が推測できるようにする」といった共通認識を持つだけでも、品質は大きく変わります。
Java varのベストプラクティス|使いどころの判断基準

java var を効果的に使いこなし、コードの品質を高めるための実践的なベストプラクティスを3つ紹介します。
適切な変数名で型を推測しやすくする
var を使う際の絶対的なルールは、変数名から型や役割が明確に推測できるように命名することです。型情報が省略される分、変数名が持つ意味の重要性が格段に増します。
【悪い例 】
var list = getUsers(); // Listであることは分かるが、何のリストか不明
var data = findById(1); // dataの中身が全く分からない【良い例 】
var userList = getUsers(); // ユーザーのリストであることが明確
var targetUser = findById(1); // 探している特定のユーザーだと分かるvarを使う場合は特に変数名の命名を意識しましょう。
varと明示的な型宣言の使い分け
「いつ var を使い、いつ明示的な型を使うべきか」という判断基準を持つのが重要です。
【var を積極的に使うべき場面】
- 右辺で
newを使っており、型が完全に明らかな場合
var user = new User("Taro");
var idList = new ArrayList<Integer>();- キャストの右辺など、型が自明な場合
var user = (User) obj;- 中間変数を一時的に格納する場合メソッドチェーンの途中結果など、その場でしか使わない変数には
varが適しています。
【明示的な型宣言を使うべき場面】
- 右辺から型が推測しにくい場合
// var result = getProcessingResult(); だと型が不明
ProcessingResult result = getProcessingResult();- インターフェース型で受けたい場合実装クラスではなく、より抽象的なインターフェースで変数を扱いたい場合は、明示的に型を宣言します。これはポリモーフィズムの観点からも重要です。
// ArrayListではなく、より汎用的なListとして扱いたい
// var names = new ArrayList<String>(); と書くと、namesの型はArrayListになる
List<String> names = new ArrayList<>();実際のプロジェクトでの活用例
実際のプロジェクトでは、Stream APIと組み合わせる場面で var が頻繁に登場します。
public List<String> getActiveUserEmails(List<User> users) {
// Stream APIの中間操作でvarを活用
var activeUsers = users.stream()
.filter(User::isActive)
.toList(); // activeUsersは List<User> 型
// 別の処理...
var userEmailMap = activeUsers.stream()
.collect(Collectors.toMap(User::getId, User::getEmail));
// さらに処理を続ける...
var sortedEmailList = userEmailMap.values().stream()
.sorted()
.toList();
return sortedEmailList;
}このように、複数の処理ステップに分ける際に、その都度生まれる中間的なコレクションを var で宣言すると、コードの流れが追いやすくなります。
もう一つ、Spring Bootでの実例を見てみましょう。REST APIの戻り値を受け取る場面では、varの効果が特に大きくなります。
// Before(var導入前)— 1行が非常に長くなる
ResponseEntity<List<UserProfileDto>> response = restTemplate.exchange(
url, HttpMethod.GET, entity,
new ParameterizedTypeReference<List<UserProfileDto>>() {});
// After(var導入後)— 型宣言が消えてすっきり
var response = restTemplate.exchange(
url, HttpMethod.GET, entity,
new ParameterizedTypeReference<List<UserProfileDto>>() {});右辺のParameterizedTypeReferenceで型が明らかなため、左辺のResponseEntity<List<UserProfileDto>>は冗長です。varを使えば、型の重複が解消されてコードが読みやすくなります。
まとめ
最後に、この記事の要点をまとめます。java var を使いこなし、より良いコードを目指しましょう。
varは便利だが「万能」ではない
var は、Javaのコードをより簡潔で読みやすくするための強力なツールです。特に、型名が長くなる場面では絶大な効果を発揮します。
しかし、それは「常に var を使うべき」という意味ではありません。可読性を下げる可能性があることを常に念頭に置き、「読み手にとって親切かどうか」を基準に、明示的な型宣言と使い分ける判断力が求められます。
初心者がつまずきやすいポイント
Javaを学び始めた方が var でつまずきやすいのは、主に以下の2点です。
今後のJava開発での位置づけ
2026年現在、Javaは半年ごとのリリースサイクル(Java 26が2026年3月リリース)を継続しており、varを前提としたコーディングスタイルが定着しています。varは2018年のJava 10導入から8年が経過し、モダンなJava開発における標準的な記法として完全に定着しました。
今後、var を適切に使いこなすスキルは、生産性の高いJavaエンジニアにとって必須のものとなるでしょう。ぜひあなたのプロジェクトでもvarを活用してみてください。