メニューを閉じる

テクノデジタルグループ

メニューを開く

2018.03.01

プログラミング

Java10でvarによるローカル変数定義が可能になるらしい

はじめまして、MTです。

Java10のリリースが近づいてきました。
予定だと2018年03月20日に正式リリースされるようです。

Java10では、以下の12個の変更が入るようです。

  • 286: Local-Variable Type Inference
  • 296: Consolidate the JDK Forest into a Single Repository
  • 304: Garbage-Collector Interface
  • 307: Parallel Full GC for G1
  • 310: Application Class-Data Sharing
  • 312: Thread-Local Handshakes
  • 313: Remove the Native-Header Generation Tool (javah)
  • 314: Additional Unicode Language-Tag Extensions
  • 316: Heap Allocation on Alternative Memory Devices
  • 317: Experimental Java-Based JIT Compiler
  • 319: Root Certificates
  • 322: Time-Based Release Versioning

今回の目玉は286の Local-Variable Type Inference でしょうか。
ローカル変数を var で定義することが可能になる、変更になります。
今回は、一足先にこの var を使ってみたいと思います。

動作環境


// OS
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.3
BuildVersion: 17D102

// Docker
$ docker -v
Docker version 17.12.0-ce, build c97c6d6

// Docker Image
$ docker pull openjdk:10
$ docker run -it openjdk:10 jshell

今回はDockerでサクッと環境を作っていますが、Early-Access版も配布されています。

従来のローカル変数定義

  String hello = "Hello";

これまでは 型 変数名 = 初期値 の形式で定義していました。

var を使ってローカル変数を定義してみる

今回の変更で、以下のようにローカル変数を定義することが可能になります。

  var hello = "Hello";

変数 hello には型が指定されていませんが、右辺の値が String 型であるため、
helloString 型の変数であるとコンパイラが推論してくれます。(型推論)

ジェネリック型のローカル変数を var で宣言する場合、
右辺で実型パラメータを与えなければ原型として定義されてしまいます。

// 右辺で実型パラメータを与える
var stringList = new ArrayList<String>();

// 実型パラメータを与えない場合は、原型として扱われる
var list = new ArrayList();  

他にも、forやtryの中でも var が使用できます。

for(var x : list){ ... }
try(var y = ...){ ... } catch ...

できないこと

基本的に型推論が効かないような宣言はできません。

  • 変数宣言時に初期値を指定しない
  • null で初期化
  • トップレベルで final 修飾する
    • final修飾は無視される
  • ラムダ式の代入
  • メソッド参照の代入
  • {}による配列の初期化
// 変数宣言時に初期値を指定しない
jshell> var number
|  Error:
|  cannot infer type for local variable number
|    (cannot use 'var' on variable without initializer)
|  var number;
|  ^---------^

// 初期値を指定するか、varではなく従来通りに定義する

// nullで初期化
jshell> var number = null
|  Error:
|  cannot infer type for local variable number
|    (variable initializer is 'null')
|  var number = null;
|  ^----------------^

// nullで初期化したい場合には、varと併用しない
Integer number = null;
// トップレベルでfinal修飾
jshell> final var number = 0
|  Warning:
|  Modifier 'final'  not permitted in top-level declarations, ignored
|  final var number = 0;
|  ^---^
number ==> 0

// 禁止されているわけではありませんが、final修飾は無効になります。
// トップレベルでなければfinal修飾が効きます
jshell> public void method(){
   ...>   final var number = 0;
   ...>   number = 1;
   ...> }
|  Error:
|  cannot assign a value to final variable number
|    number = 1;
|    ^----^

// ラムダ式の代入
jshell> var func = value -> value.toString()
|  Error:
|  cannot infer type for local variable func
|    (lambda expression needs an explicit target-type)
|  var func = value -> value.toString();
|  ^-----------------------------------^

// ラムダ式とvarは併用しない
Function func = value -> value.toString();

// メソッド参照の代入
jshell> var func = Object::toString
|  Error:
|  cannot infer type for local variable func
|    (method reference needs an explicit target-type)
|  var func = Object::toString;
|  ^--------------------------^

// メソッド参照とvarは併用しない
Function func = Object::toString;

// {}による配列の初期化
jshell> var array = {0, 1, 2}
|  Error:
|  cannot infer type for local variable array
|    (array initializer needs an explicit target-type)
|  var array = {0, 1, 2};
|  ^--------------------^

// ちゃんと型を明示しましょう
jshell> var array = new int[]{0, 1, 2};
array ==> int[3] { 0, 1, 2 }

 

var 以外にも検討されていたみたい

There was a diversity of opinions on syntax.
The two main degrees of freedom here are what keywords to use (var, auto, etc),
and whether to have a separate new form for immutable locals (val, let).
We considered the following syntactic options:

  • var x = expr only (like C#)
  • var, plus val for immutable locals (like Scala, Kotlin)
  • var, plus let for immutable locals (like Swift)
  • auto x = expr (like C++)
  • const x = expr (already a reserved word)
  • final x = expr (already a reserved word)
  • let x = expr
  • def x = expr (like Groovy)
  • x := expr (like Go)

After gathering substantial input, var was clearly preferred over the Groovy, C++, or Go approaches. There was a substantial diversity of opinion over a second syntactic form for immutable locals (val, let); this would be a tradeoff of additional ceremony for additional capture of design intent. In the end, we chose to support only var. Some details on the rationale can be found here.

最終的には var だけ導入する結論になったようです。
個人的には、イミュータブルな変数を定義できるようなモノも追加してほしかったです…。(Scalaの val や、Swiftの let みたいな)

所感

今まで冗長だった変数定義が、スマートになるのはいいことですね。
個人的には var 導入によるデメリットは無いように感じました。
今後もこのような「より楽にコードを書くための」変更が入ってくるようなので、楽しみですね。

余談

var で定義されたローカル変数は、コンパイルされるとどうなるか気になったので調べてみました。

結論から言うと、var で定義されたローカル変数はコンパイル後に 型 変数名 = 初期値 の形式になります。
例えば以下のようなコードをコンパイルすると、


public class MyClass {
    public static void main(String...args){
        var number = 0;
        var string = "Hello World";
        System.out.println(number);
        System.out.println(string);
    }
}

以下のようなコードにコンパイルされます。(実際はバイトコードです)


public class MyClass {
    public MyClass() {}
    public static void main(String... var0) {
        byte var1 = 0;
        String var2 = "Hello World";
        System.out.println(var1);
        System.out.println(var2);
    }
}

変数 numberbyte型に、stringString になってますね。


【記事への感想募集中!】

記事への感想・ご意見がありましたら、ぜひフォームからご投稿ください!
  • こんな記事が読んでみたい、こんなことが知りたい、調べてほしい!という意見も募集中!
  • いただいた感想は今後の記事に活かしたいと思います!

感想フォームはこちら


【テクノデジタルではエンジニア/デザイナーを積極採用中です!】

下記項目に1つでも当てはまる方は是非、詳細ページへ!
  • 自分でアプリを作ってみたい
  • ITで世の中にワクワクを生み出したい
  • 使いやすさ、デザインにこだわったWebサイトを開発したい

採用情報の詳細はこちら


Qangaroo(カンガルー)

  • 徹底した見やすさと優れた操作性で、テストの「見える化」を実現。
  • テストの進捗が見える。開発がスマートに進む。
  • クラウド型テスト管理ツール『Qangaroo(カンガルー)』

【テクノデジタルのインフラサービス】

当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。

https://www.tcdigital.jp/infrastructure/

最近の記事