Java類型推斷是一項推薦的Java特性,允許開發人員使用var關鍵字代替顯式的變量類型聲明。最近的報道顯示,由於社區內無法就區分可變和不可變變量的實現方式達成一致意見,Java類型推斷將不再支持使用關鍵字區分可變的和不可變變量。提議的一些用來表示不可變變量的關鍵字包括val和let。為了避免對細枝末節的長期討論,一些這樣的例子將被排除以求簡潔。盡管JEP並沒有透露目標版本,Java 10可能會實現這些功能。
為了完整地定義JEP 286的范圍,甲骨文公司的Java語言架構師Brian Goetz在經過了一系列的提議和咨詢之後了解到,實現局部變量類型推斷(和避免顯式聲明變量類型的步驟)的新功能已達成足夠共識,該功能應該使用關鍵詞var。另外,社區還強調了他們希望使用和其它語言,如Scala、Kotlin或JavaScript,一樣的方式來區分可變和不可變變量的類型推理。然而,盡管大家贊同這是一個有用的功能,但是就如何實現該區分,沒有一致的意見。var/val、var/let和(raw type)/var都有強烈的支持者和反對者。為了防止這種爭論延遲類型推斷的進展,該功能的主導者決定將范圍縮小到局部變量的簡單類型推斷,不管可變性區別。盡管如此,使用稍長一點的構造final var,不可變的局部變量的類型仍然是可推斷的。
var s = "hello"; // type of s is String
var keys = map.keySet(); // assuming map is of type Map<K, V>, type
// inferred for keys will be Set<K>
final var MAX_COUNT = 100L; // MAX_COUNT will be immutable long
更新還用於提醒可推斷的程度。一方面,只有初始化信息將用於推斷變量的類型;這意味著在聲明時未初始化的變量需要顯式聲明類型,它也有助於防止一些潛在的晦澀的錯誤(例如,代碼深處的變量的類型推斷錯誤)。另一方面,只有局部變量的類型是可推斷的,不包括屬性和方法,這是基於如下理解的。屬性和方法是類的公共接口的一部分,因此需要由程序員明確定義。類型推斷不起作用的其他情況是,暗示自身類型的初始化表達式,如:
List<String> list = new LinkedList<>(); // type not indicated in
// initialisation, but inferred
// from variable declaration
var list = new LinkedList<>(); // error, impossible to infer a type for
// the contents of the list
Function<String, Integer> f = s -> s.length(); // type of s and length
// inferred from
// declaration
var f = s -> s.length(); // error, type of s unknown, return type of
// length unknown
int[] array = {1, 2, 3}; // 1, 2, 3 interpreted as integers
var array = {1, 2, 3}; // error, poly expressions not supported
// (see below)
// Use Integer.valueOf(int)
Function<Integer, Integer> intFunction = Integer::valueOf;
// Use Integer.valueOf(String)
Function<String, Integer> stringFunction = Integer::valueOf;
// error, ambiguous initialisation
var function = Integer::valueOf; // unable to know which overloaded
// version of valueOf should be used
目前還不清楚是否將支持上述的某些特定例子。如Goetz所說,“我們將初始化器看作一個獨立表達式(standalone expression),通過獲取它的類型得到變量的類型。然而,數組初始器與lambda和方法引用一樣,是多變表達式(poly expression),所以被拒絕了。”多變表達式是Java 8中隨著lambda引進的一個概念,與普通表達式的不同之處在於計算類型的方式。對於普通表達式來說,可以通過在編譯時檢查表達式的內容獲取類型;對於多變表達式,要計算類型,除此之外還需要目標類型(即被表達式賦值的變量的類型)。這意味著,多變表達式已經隱含了一些對自身的類型推斷,因此很難甚至不可能推斷多變表達式的類型。但是,有一些這類問題的場景似乎提供了足以推斷出合適類型的信息,可能將來會考慮把它們納入進來。如下:
var a = {1, 2, 3}; // could infer type int[]
var f = (String s) -> s.length(); // could infer type
// Function<String, Integer>
盡管存在局限,局部類型推斷能幫助縮小Java和其它JVM語言之間的差距,為Java開發人員減少冗余代碼。和lambda現在擴充新功能的方式一樣,類型推斷可能在第一版之後得到提升。這將確認作為新功能實驗場所的JVM語言的非官方動態,最流行的新功能最終被引入Java。
查看英文原文:Java Type Inference Won't Support Mutability Specification