2024.11.14
いまさらNode.jsを知ろう~環境構築も~
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
型であるため、
hello
が String
型の変数であるとコンパイラが推論してくれます。(型推論)
ジェネリック型のローカル変数を 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);
}
}
変数 number
は byte
型に、string
は String
になってますね。
【記事への感想募集中!】
記事への感想・ご意見がありましたら、ぜひフォームからご投稿ください!【テクノデジタルではエンジニア/デザイナーを積極採用中です!】
下記項目に1つでも当てはまる方は是非、詳細ページへ!Qangaroo(カンガルー)
【テクノデジタルのインフラサービス】
当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。
最近の記事
タグ検索