Local Variable Type Inference -- Java 10後加入的var識別字
Overview
在JDK10後,我們可用var這個識別字宣告區域變數了!
在接下來的段落,我們將細述此語法更新並佐以範例code。
Introduction
在Java 9 以前,我們宣告區域變數必須一併指定他的型別,並確保型別與等號右側的initializer一致。
如:
String message = "Good bye, Java 9";
在Java 10後,可以這樣宣告區域變數:
var message = "Hello, Java 10";
也就是說我們不提供變數的資料型別在等號左側,透過標記變數為var, 編譯器會就等號右側的initializer推論出變數的資料型別。
(如在上述的範例,編譯器會判斷message變數為String。)
透過使用var,可以讓我們的程式更簡潔。
像是下面這段有點冗長難讀的code
URL url = new URL("http://www.oracle.com/");
URLConnection conn = url.openConnection();
Reader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
我們可以用識別字var改寫成
var url = new URL("http://www.oracle.com/");
var conn = url.openConnection();
var reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
需注意的是,var這個識別字僅提供給區域變數使用。
即var不能用在成員變數(member variables)和方法的參數與回傳型別。
還有Java仍然是靜態的語言。使用var時要讓編譯器有足夠的資訊判斷變數的型別。
此外,var並非java中的關鍵字(keyword ),這確保了他的向前相容性。
如果之前寫的程式中有用var當變數名稱、方法名稱,或是package的名稱用var命名,皆不會因為這次的語法新增而受影響。
但若曾用var作為類別名稱或介面名稱,則需重新命名。
Example
var 的用法有:
(1) 宣告區域變數,並且等號右側有非空的initializers
var list = new ArrayList<String>(); // infers ArrayList<String>
var stream = list.stream(); // infers Stream<String>
var path = Paths.get(fileName); // infers Path
var bytes = Files.readAllBytes(path); // infers bytes[]
(2)用於for each寫法
List<String> myList = Arrays.asList("a", "b", "c");
for (var element : myList) {...} // infers String
(3) 傳統for迴圈
for (var counter = 0; counter < 10; counter++) {...} // infers int
(4) 嘗試關閉資源(try-with-resources)語法
try (var input =
new FileInputStream("validation.txt")) {...} // infers FileInputStream
(5) lambda寫法的形式參數(formal parameter)宣告
(x, y) -> x.process(y)
可改寫成
(var x, var y) -> x.process(y)
但不可寫成
(var x, y) -> x.process(y) // Cannot mix var and inferred formal parameters
// in implicitly typed lambda expressions
(var x, int y) -> x.process(y) // Cannot mix var and manifest types
// in explicitly typed lambda expressions
即隱含型別Lambda表示式(implicitly typed lambda expression)裡的形式參數們必須都使用var或是都不使用,維持原寫法,
不在參數前加任何型別。
此項寫法是在JDK 11後才允許的,詳細描述於 JEP 323,或可參考 Java 11 - Local-Variable Syntax for Lambda Parameters (JEP 323)。
Illegal Use of var
下面是var的幾個錯誤用法
• 沒有initializer:
var n;
• 用null初始化變數:
var emptyList = null;
• 不是區域變數
public var = "hello";
• Lambda 表示式的目標型態必須明確
var p = (String s) -> s.length() > 10; // error: lambda expression needs an explicit
• 陣列 initializer的目標型態必須明確
var arr = { 1, 2, 3 }; // error: array initializer needs an explicit target-type
關於Lambda 表示式和陣列 initializer的等號左側不可用var,可參考Oracle 的Java 語言架構師Brian Goetz在
Reader Mail Bag for Thursday (ThuMar 10 15:07:54 UTC 2016) 問題7中的說明。
Conclusion
JDK10後,var識別字的加入,讓我們撰寫code更便利,使用得當,可以令程式更易閱讀。
但var的使用僅限於區域變數,須注意使用規則,尤其確保型別是可以被編譯器推斷出來的。
水能載舟、亦能覆舟,var使用不當,也可能造成程式難閱讀,進而不好除錯。
關於用var宣告區域變數對周遭程式的影響及使用準則可參考 Style Guidelines for Local Variable Type Inference in Java
資料來源 :