1. 概要

JDK 10の最も目に見える拡張機能の1つは、初期化子を使用したローカル変数の型推論です。

このチュートリアルでは、この機能の詳細と例を示します。

2. 序章

Java 9までは、ローカル変数のタイプを明示的に記述し、それを初期化するために使用される初期化子と互換性があることを確認する必要がありました。

String message = "Good bye, Java 9";

Java 10では、次のようにローカル変数を宣言できます。

@Test
public void whenVarInitWithString_thenGetStringTypeVar() {
    var message = "Hello, Java 10";
    assertTrue(message instanceof String);
}

メッセージのデータ型は提供していません。 代わりに、メッセージ var としてマークし、コンパイラーは右側にある初期化子のタイプからメッセージのタイプを推測します。

上記の例では、メッセージのタイプはStringになります。

この機能は、初期化子を使用するローカル変数でのみ使用できることに注意してください。 メンバー変数、メソッドパラメーター、戻り型などには使用できません。初期化子が必要です。これがないと、コンパイラーは型を推測できません。

この機能強化は、ボイラープレートコードの削減に役立ちます。 例えば:

Map<Integer, String> map = new HashMap<>();

これは次のように書き直すことができます。

var idToNameMap = new HashMap<Integer, String>();

これは、変数の種類ではなく、変数名に焦点を当てるのにも役立ちます。

もう1つの注意点は、 varはキーワードではないということです。これにより、関数または変数名としてvarsayを使用するプログラムの下位互換性が保証されます。 var は、 int と同様に、予約済みの型名です。

最後に、あることに注意してください varを使用する際の実行時のオーバーヘッドはなく、Javaを動的型付け言語にすることもありません。 変数のタイプはコンパイル時に推測され、後で変更することはできません。

3. varの不正使用

前述のように、varはイニシャライザがないと機能しません。

var n; // error: cannot use 'var' on variable without initializer

nullで初期化した場合も機能しません。

var emptyList = null; // error: variable initializer is 'null'

非ローカル変数では機能しません:

public var = "hello"; // error: 'var' is not allowed here

Lambda式には明示的なターゲットタイプが必要であるため、varは使用できません。

var p = (String s) -> s.length() > 10; // error: lambda expression needs an explicit target-type

配列初期化子の場合も同じです。

var arr = { 1, 2, 3 }; // error: array initializer needs an explicit target-type

4. varの使用に関するガイドライン

var を合法的に使用できる場合もありますが、そうすることはお勧めできません。

たとえば、コードが読みにくくなる可能性がある状況では、次のようになります。

var result = obj.prcoess();

ここでは、 var を合法的に使用していますが、 process()によって返される型を理解することが難しくなり、コードが読みにくくなります。

java.net には、 Javaでのローカル変数型推論のスタイルガイドラインに関する専用の記事があり、この機能を使用する際の判断の使用方法について説明しています。

var を回避するのが最善の別の状況は、パイプラインが長いストリームにあります。

var x = emp.getProjects.stream()
  .findFirst()
  .map(String::length)
  .orElse(0);

var を使用すると、予期しない結果が生じる可能性があります。

たとえば、Java7で導入されたdiamond演算子で使用する場合は次のようになります。

var empList = new ArrayList<>();

のタイプ empList になります配列リストではなくリスト 。 私たちがそれをしたいのなら配列リスト 、明示的にする必要があります:

var empList = new ArrayList<Employee>();

var を表示できないタイプで使用すると、予期しないエラーが発生する可能性があります。

たとえば、匿名クラスインスタンスで varを使用する場合:

@Test
public void whenVarInitWithAnonymous_thenGetAnonymousType() {
    var obj = new Object() {};
    assertFalse(obj.getClass().equals(Object.class));
}

ここで、別のObjectobjに割り当てようとすると、コンパイルエラーが発生します。

obj = new Object(); // error: Object cannot be converted to <anonymous Object>

これは、objの推定タイプがObjectではないためです。

5. 結論

この記事では、新しいJava10ローカル変数型推論機能と例を紹介しました。

いつものように、コードスニペットはGitHubにあります。