自從JDK6之後,後續重大版本釋出前的固定戲碼,就是延期、延期、再延期,然而,自JDK9起,局勢有了重大轉變。不單是因為模組化實質上構築了新的Java平臺,後續的JDK版本在釋出週期上,也有了變化。

從JEP223到JEP322

自Java江山易主,版本的字串命名方式一直是耐人尋味的話題。單就下載JDK時,所看到的簡短版本字串形式來說,在7u40版本之前,u之後的數字,代表JDK是發布以來第幾個修正版,然而Oracle改變規則,為了彰顯出安全之類的重大修補(Critical Patch Updates)版本,採用奇數來命名,而臭蟲修正、API修改之類的維護版本,數字是偶數(另有版本號$MAJOR.$MINOR.$SECURITY格式,區分臭蟲修正或API修改)。

為此,之前既有的JDK6/7釋出版本,還被重新命名。就結論而言,重新命名之後,從7u9、6u37開始,就可以從奇偶數來辨別是否為重大修補版本;至於7u40之後的版本,重大修補是基於5的倍數,遇偶數加一,而維護版本會是20的倍數,如此(不直覺)的命名方式,被規範在JEP223之中。

然而,自JDK8之後,Oracle的Java架構長Mark Reinhold希望,未來Java發布可以基於時間,以半年為週期,持續發布新版本,讓一些有用的小特性,也能被開發者使用,因此,JEP 223的規範就不再適用了,而在JDK9釋出後,他們針對新版本曾經提出了基於$YEAR.$MONTH格式,然而,受到了社群極大的反對,為此,還提出了三個替代方案,收集各方意見(https://goo.gl/7CA8B3)。

那麼,Java下一個特性版本是?8.3?1803?還是10?調查結果顯示,社群大多數都支持10,Stephen Colebourne也發出懇求(https://goo.gl/i5J44T),並表示Java不像Ubuntu這類作業系統,基於$YEAR.$MONTH格式並不適合;到了最後定案,是採$FEATURE.$INTERIM.$UPDATE.$PATCH格式,規範在JEP322之中。

JEP322跟JEP223的命名格式上,有點類似,然而是基於時間,$FEATURE每六個月變更一次,必須包含新增的特性,$INTERIM目前總是為0,保留這個項目是作為未來使用之彈性,同一$FEATURE下,$UPDATE每三個月遞增一次,包含安全、臭蟲修正,而$PATCH只會在緊急的重大修補時遞增。

因此,對於Java SE 9來說,目前可以看到的版本,會是9.0.4這類的格式,至於2018年3月發布的特性版本為10,到了9月提供的新版本,就是11,JDK11預計會是長期支援版本,所以,在版本字串上,也會特別顯示LTS(long-term support)。

JDK10的var特性

無論如何,主版本是維持在大家熟悉的流水號格式了,而基於時間的釋出,可以看出Java想一掃過去總是延期的沉重感。然而,沉重並不只來自版本號,也來自於新興語言中靈活語法特性,帶來的壓力。基本上,Java對於語法新增,極為嚴苛看待,除非該語法被認為對開發產生極大助益,才有可能加入Java,不然,就會採用程式庫來加以實現。例如,在JDK8中實現了Optional,而不是讓多數開發者希望的貓王運算子(Elvis operator)?:成為語法之一。

然而,自JDK9之後,一些有趣的JEP引發了Java社群的熱議,像是JEP286中的var,用於區域變數型態推斷(Local-Variable Type Inference),例如, var name = "Justin",乍看與JavaScript沒有兩樣,然而,雖然沒有宣告型態,name的型態卻是String,這是從等號右邊的值推斷而來。

如果是泛型,我們可以撰寫為var names = new ArrayList<String>()這樣的形式,接著,names的型態上,就會自動推斷為ArrayList<String>。而對於更複雜的泛型應用,例如:如果我們撰寫成var nickNames = usernames.stream().map(this::getNickName).filter(Optional::isPresent),此時,編譯器所能自動推斷的nickNames形態,應會是Stream<Optional<String>>,若要進一步操作nickNames,結合開發工具提示,撰寫會簡潔許多。

更進一步地,var還讓匿名類別語法使用上更有彈性,可用來臨時擴充類別的特性或行為。

例如,底下語法可像JavaScript那樣臨時建立物件,並具有name、score特性與toXML方法,可透過o.name、o.score來存取,或用o.toXML()呼叫方法:

var o = new Object() {
String name = "Justin";
Double score = 88.5;
String toXML() {
return String.format(
"<name>%s</name><score>%.2f</score>", name, score);
}
};

這樣的語法可以運作的原理在於,匿名類別語法確實建立了一個匿名型態,只是在過去,開發者無法撰寫匿名型態的名稱來宣告變數,現在有了var自動推斷型態,變數可以自動獲取匿名型態,也就可以透過該變數來操作匿名型態上定義的成員。

如果使用過Scala、Kotlin之類的語言,對var應該不陌生,Java後來吸納這個特性,並由JDK10實現(社群進一步地期待可以有val來取代final),雖然只能用在區域變數(也就能用在for與try的宣告區),但就保守的Java來說,這已是跨出一大步。

未來的JDK

基於時間而發布的JDK,期盼每個版本都要有一到兩個重要功能,預計在9月發布的JDK11,目前已看到納入的JEP,有JEP323,可以在Lambda表示式的參數部份使用var,為的是有利於標註的修飾,可加註在Lambda表示式的參數之上。

比較要注意的是JEP320!JDK9已標註為廢棄的Java EE與Corba相關模組,將會在JDK11移除,在過去,Java有些API被廢棄,然而鮮少真正移除,就Java目前極力想展現輕盈來看,其他標示為廢棄的API,在未來的JDK版本,移除的可能性也會增加。

實際上,在JDK9模組化中,許多JDK內部API已經受到模組化的限制,而無法使用,或是使用時產生警訊。雖然可透過其他方式(像是非標準引數)繞過限制或警訊,然而,在未來版本JDK中,繞道而行的方式會移除,或者警訊將成為禁用。這些都意味著,Java想跳舞不單只是語法層面,還包含了平臺本身,為此,開發者本身也得及早因應。

雖然目前未出現在JDK11,但讓Java看來極力展現輕盈的JEP,還包含了JEP305的Pattern Matching,以及JEP325的Switch Expressions,對於用過Scala的開發者並不陌生。另外,還有個Java社群始終想要、卻死不加入的特性,也就是JEP326提出的Raw String Literals,開發者將來有機會擺脫惱人的字元跳脫(escape),以及用+來組成多行字串。

甚至還有個JEP草案,建議使用java HelloWorld.java來執行程式,而不用透過javac -d、java -cp……的形式,這讓人想到JDK9中附上的jshell,便於測試一些小程式。實際上,應該從JDK8開始,Java就試圖展現輕盈,Lambda語法及Stream相關API無非就是要素,就現在回顧,它們確實能極大程度來改變開發的風格與形式,並從中獲益,所以,JDK9的模組化,對於JDK本身的精簡,就更不在話下了。

Java已經歷經二十幾個年頭了,至今仍是重要的語言及平臺,若依然極力展現跳舞的努力及可能性,當然是好事,然而,更進一步該思考的是,為什麼一向被認為笨重的Java,也想努力舞動?

仔細瞭解加入Java、對開發程式有著重大影響的新語法,以及API、程式庫、模式、典範,知道它們從何而來、為了進入Java而做的改變,甚至作為重構既有程式的工具,試著探討與辨識,到底是哪些要素對Java產生如此強大的刺激,令它也想隨之起舞!

專欄作者

熱門新聞

Advertisement