本ページはプロモーションが含まれています

Java入門

【Java 10以降】varの使い方をマスター!コードが劇的に変わるコツ

トム

・SaaS勤務/javaのバックエンドエンジニア
/java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎

「最近のJavaコードでよく見かける var って何だろう?」

var を使うと何が良いの?逆に注意すべき点はある?」

Javaでの開発経験が10年以上ある私も、Java 10で var が導入された当初は、その使い方に少し戸惑いを感じました。しかし、いくつかのプロジェクトで積極的に活用し、チーム内で議論を重ねるうちに、コードの可読性を劇的に向上させる強力な武器になると確信したのです。

この記事を読めば、Javaのvarの使い方に迷っている方や、もっと簡潔なコードを書きたいと思っている方が、var の基本から実務で役立つベストプラクティスまで体系的に学べます。あなたのJavaコーディングを、今日から一段階レベルアップさせましょう。

varとは?Javaに導入された背景

var は、Java 10から導入された「ローカル変数型推論」のための機能です。変数を宣言する際に、型の代わりに var と記述すると、コンパイラが初期化の値から自動的に型を判断(推論)してくれます。

これは、Javaが動的型付け言語になったわけではありません。あくまでコンパイル時に型が決定される静的型付け言語である点は、今までと全く同じです。コードの記述量を減らし、より現代的なプログラミングスタイルを可能にするために導入されました。

varが使えるようになったバージョン(Java 10)

var は、2018年にリリースされた Java 10 で正式に導入されました。そのため、Java 9以前の環境では使用できません。

長期サポート(LTS)バージョンであるJava11から本格的に普及しはじめ、今では多くのプロジェクトでごく普通に使われる機能となっています。これからJavaを学ぶ方や、新しいバージョンの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の var は、あくまで型宣言を省略するためのシンタックスシュガー(糖衣構文)であると覚えておきましょう。

varの基本的な使い方

それでは、java 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>型
}
  • 拡張for文
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);
}
// NG! ラムダ式の引数にvarは使えない(Java11以降は一部可能ですが、通常は型を明記します) 
(var x, var y) -> x + y;

配列・ジェネリクスでのvar利用例

var は、特に型名が長くなりがちなジェネリクスや配列で真価を発揮します。コードが非常にすっきりと読みやすくなるのが分かります。

  • ジェネリクスでの利用ArrayListHashMapのような、ジェネリクスを使った複雑な型宣言がとてもシンプルになります。右辺の型定義は省略できない点に注意してください。
// 従来
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を使うメリットとデメリット

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 の使用を許可するか
  • どのような場面では明示的な型宣言を必須とするか

上記のようなルールをチームで共有しておかなければ、人によって書き方がバラバラになり、コードベース全体の可読性やメンテナンス性が低下する原因となります。「var を使っても良いが、変数名で型が推測できるようにする」といった共通認識を持つだけでも、品質は大きく変わります。

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 を使い、いつ明示的な型を使うべきか」という判断基準を持つのが重要です。

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 で宣言すると、コードの流れが追いやすくなります。

まとめ

最後に、この記事の要点をまとめます。java var を使いこなし、より良いコードを目指しましょう。

varは便利だが「万能」ではない

var は、Javaのコードをより簡潔で読みやすくするための強力なツールです。特に、型名が長くなる場面では絶大な効果を発揮します。

しかし、それは「常に var を使うべき」という意味ではありません。可読性を下げる可能性があることを常に念頭に置き、「読み手にとって親切かどうか」を基準に、明示的な型宣言と使い分ける判断力が求められます。

初心者がつまずきやすいポイント

Javaを学び始めた方が var でつまずきやすいのは、主に以下の2点です。

ポイント

  1. 何でも入る型だと誤解してしまう: var は静的型付けであり、一度決まった型は変更できません。JavaScriptの感覚で使わないようにしましょう。
  2. 使えない場所で使おうとする: var はローカル変数専用です。フィールドやメソッドの引数・戻り値には使えないルールをしっかり覚えてください。

今後のJava開発での位置づけ

Javaのバージョンアップは続いており、プログラミングスタイルも時代と共に変化しています。var は、もはや特殊な機能ではなく、モダンなJava開発における標準的な記法の一つです。

今後、var を適切に使いこなすスキルは、生産性の高いJavaエンジニアにとって必須のものとなるでしょう。この記事を参考に、ぜひあなたのプロジェクトでも var を活用してみてください。コードを書くのが、きっと今よりもっと楽しくなるはずです。

  • この記事を書いた人
  • 最新記事

トム

・SaaS勤務/javaのバックエンドエンジニア
/java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎

-Java入門