程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在不改變語言的前提下如何推進Java的不斷演進

在不改變語言的前提下如何推進Java的不斷演進

編輯:關於JAVA

James Gosling在“The Feel of Java”中說到:

Java是一種藍領語言,它並非博士的論文素材而是用於完成工作的語言。各式各樣的程序員都非常熟 悉Java,因為在設計Java之初我就堅持這樣一種觀點:選擇久經考驗的東西而非僅僅是聽起來很美。

Java所獲得的巨大成功證明了這種設計方式是正確的,但如果這依然是當今Java的重要目標的話,那 麼其結果就是語言的演進將變得非常緩慢。除此以外,Java是一門成熟、使用廣泛的語言這個事實也將導 致其演進過程充滿了困難。一方面,添加到語言中的每個特性都可能在一定程度上造成不可預料的結果, 這麼做會疏遠那些已經使用了該語言的開發者。另一方面,本身很完美的特性可能在同語言中的其他特性 進行交互時產生不可預料的結果。更糟的是,一旦增加了某個語言特性,幾乎就不可能再將其移除了,即 便是該特性會對整個語言產生不利影響也沒辦法。為了證明某個新特性是正確的,語言設計者必須確信從 長遠來看,該特性會給語言帶來好處,而不是短期效益或是針對某個問題的快速解決方案,之後就變得可 有可無了。為了降低風險,語言設計者通常都會創建單獨的一種語言或是分支來進行試驗,比如Pizza語 言就是在實現前用來測試Java泛型的。這種方式的問題在於試驗的參與者非常小眾並且都是自己想參與進 來的;顯然他們對語言特性很感興趣,很多人都是學者或研究員。但是,在普通的程序員開始使用這些特 性時,那些學者或是研究員認為很棒的特性可能會變得很糟。

為了直觀感受一下這種情況,請考慮關於Java 7閉包特性的激烈爭論。一段時間以來,有人在提案中 給出了閉包的實現,但最終卻還是沒有達成共識。隨後,Sun決定不打算在JDK 7中添加完整的閉包支持。 這時爭論的焦點轉向為Java是否變得越來越復雜了,在Java 5中添加泛型(尤其是通配符語法)時就已經 出現了這種爭論;在Java已經通過匿名內部類部分實現該功能的情況下,完整的閉包支持是否是正確的呢 。需要完整閉包支持的兩個重要場景是簡化fork/join API(添加到了JDK 7中以改進多核編程)的使用以 及輔助資源的清理。Josh Bloch的ARM block提案(期望通過Project Coin加入到JDK 7中)就第二個問題 給出了另一種解決方案。Cliff Click博士在面向Java的可擴展、非阻塞編程風格的研究中給出了關於 fork/join的另一種方案,隨著處理器核心數的不斷增 加,這種方案看起來更合理。如果這一切都成為可 能的話,那麼Java中使用閉包的地方將變得非常少了,語言根本沒必要提供這個特性。

話雖如此,但對於編程語言來說,持續不斷地平穩發展還是非常重要的。因此本文探究了如下3種技術 以向Java中增加新的語言特性而又不改變語言本身,他們 是客戶化領域特定語言(DSL)、Java 6的注解 處理器(通過庫來增加可選的語言特性)以及將語法糖從語言遷移到IDE中。每項技術都可以讓眾多的主 流開發者以非侵入的方式體驗這些新特性,最棒的想法則可以融入到語言核心當中。

客戶化DSL

在這3項技術中,人們談論最多的還是DSL。該術語的確切含義至今尚未統一,但出於討論的目的,我 們在這裡簡單地把它看作是用於解決特定問題、應用范圍很窄 的一種語言而非用於解決所有計算問題的 通用語言。這樣,DSL就並非是圖靈完備(non-Turing complete)的。當然了,還是會有一些邊際情況存 在的,比如說Postscript是一種圖靈完備的語言, 但根據我們方才的定義,它也是一種DSL。

如上所述,DSL並非新概念。其他類似的DSL還有正則表達式、XSLT、Ant以及JSP等等,所有這些都需 要某種客戶化的解析器對其進行處理。Martin Fowler還說fluent interfaces/API也可以看作是另一種 DSL,稱之為內部DSL。他說內部DSL是直接在宿主語言中開發出來的。這對於Lisp和 Smalltalk開發者來 說很容易理解,而最近Ruby社區也開始對內部DSL情有獨鐘了。

雖然很多知名的DSL都是由商業公司開發和維護的,但一些企業開發團隊也已經使用該技術來創建能夠 快速解決其問題的語言了,但畢竟還是小眾,這可能是 DSL領域門檻比較高的緣故吧。負責DSL的團隊必 須要設計語言、構建解析器和其他工具來支持開發團隊,還要對每個新員工進行培訓,讓其了解DSL的工 作機理。這時,湧現出了能夠支援DSL開發的工具,這極大地改變了當前的狀況。Intentional Software 所開發的Intentional Domain Workbench比Java還要久遠,它首度實現了該工具的功能。該項目創建於微 軟研究院,Charles Simonyi博士在1995年所發表的論文“The Death of Computer Languages, the Birth of Intentional Programming”描 繪了其願景。2002年,Simonyi創建了Intentional Software以 繼續實現其想法,大家可以看看介紹該系統的視頻,極具震撼力。目前該產品的版本是1.0,但只有極少 數的合作者能夠訪問。

其他一些軟件公司也在研究這個概念,其中就包括以IntelliJ IDEA Java IDE而揚名天下的JetBrains ,JetBrains最近發布了Meta Programming System(MPS)1.0版。MPS並沒有使用解析器而是直接使用了 Abstract Syntax Tree(AST)。它提供了一個類似於文本的投影編輯器(projectional editor)以便程 序員能夠操縱AST,同時該編輯器也可用於編寫語言和程序。當程序員使用投影時就會為樹上的每個節點 創建一個文本投影,這樣變換就會反映到節點當中。開發者可以通過這種方式以任意組合(通常稱之為語 言組合)擴展和嵌入語言。JetBrains正在內部使用該產品,最近發布的bug追蹤產品YouTrack就是使用該 系統開發的。

Java 6注解處理器

相對於Ruby、Smalltalk和Lisp來說,DSL在很多主流語言(如Java)中的流行程度就稍遜一籌了,但 最近Java語言的一些變化(尤其 是Java 6中新增的注解處理器)為開發者提供了新的機遇以在其中使用 DSL。對於Java EE 6中的JPA 2.0來說,其某些API本身就是 DSL。注解處理器會為應用中的每個持久化類 建立一個元模型類型(metamodel type)。雖然開發者可以手工處理Java中的元模型,但這實在太無聊而 且極易出錯。注解處理器的出現改變了這一切,因為它內建於Java 6,因此無需特殊的IDE支持——IDE會 代理編譯器所觸發的注解處理器,之後會自動生成元數據模型。

程序庫也可以通過注解處理器來提供新的語言特性。比如說,Bruce Chapman的原型“no closures” 提案就憑借該技術將方法轉換為 Single Abstract Method(SAM)類型,然後在Java 6上編譯。在與其交 談過程中,Chapman指出SAM類型還支持自由變量(free variable),這是閉包的一個關鍵技術:

除了Single Abstract Method所需的參數外,方法體還可以通過@As.Additional注解聲明額外的參數 。在獲得SAM類型的實例時,這些參數可以帶有綁定值,然後 在每次調用時傳遞給方法。

Chapman還創建了Rapt項目以探索該技術的其他使用場景,同時為語言的兩個變化提供了自己的實現— —多行字符串(Multiline Strings)與XML字面值(XML literals)——這兩個特性是 為JDK 7准備的, 但卻不會包含到最終的發布中。Java甚至也可以使用這種方法實現閉包,Chapman對此說到:

我們剛剛使用該技術完成了一個Swing項目,在這個過程中發現了泛型的一些小bug,其中一個bug還沒 有修復,除此之外一切都很棒,沒人再想使用傳統 的匿名內部類了。

另一個探究注解處理器的項目是Lombok,它將該技術又向前推進了一大步。Lombok將注解作為回調以 運行Java agent,後者會根據注解重寫各種javac內核。由於操縱的是內部類,因此它不太適合於產品使 用(JVM各個小版本中的內部類也可能不一樣),但該項目對於注解處理器到底能做什麼這個問題上還是 頗具啟發意義的,包括:

通過@Getter和@Setter注解定義各種訪問級別的屬性,如@Setter(AccessLevel.PROTECTED) private String name;

@EqualsAndHashCode注解會根據對象中的屬性實現hashCode()和 equals()方法

@ToString注解會實現toString()方法

@data方法相當於 @ToString、@EqualsAndHashCode、所有屬性的@Getter以及所有非final屬性的 @Setter的集合,可以使用 @data方法和構造方法初始化final屬性

還可以通過這種方式進行其他的語言試驗,比如移除Java中的非運行時異常等。

雖然注解處理器技術為語言試驗開辟了一條新航線,但還是要注意生成代碼的可讀性,保證開發者能 讀懂生成的代碼。Chapman給出了很多建議:

要生成源代碼而不是字節碼,注意生成代碼的格式(尤其是縮進)。編譯器不在乎生成的代碼是不是 都在同一行,但用戶在乎。我甚至還使用注解處理器在恰當的地方增加了一些注釋和javadoc。

如果這項技術逐漸流行起來,用戶將可以通過IDE查看編譯期所生成的代碼。

IDE中的語法糖

Bruce Chapman還提到了第三項技術——將語法糖從語言遷移到IDE中——他在博客中對該問題做過深 入闡述。對於Java IDE來說,生成部分樣板代碼已成為不可或缺的功能了,比如類的getters和setters, 但IDE開發者剛剛開始深挖該這個概念。 JetBrains的IntelliJ 9為內部類提供了一個類似於閉包的簡潔 的代碼塊語法,開 發者也可以自己加。就像代碼折疊一樣,該語法會擴展到編譯器能夠處理的完整的匿 名內部類——這樣堅持使用標准的匿名內部類語法的開發者很容易就適應了。 Eclipse也有一個類似的插 件。關鍵在於這種語法僅僅是實際代碼的另一種展示方式而已,編譯器和任何源代碼管理工具都能夠像以 前那樣處 理他們。開發者可以在兩種方式間自由切換(就像代碼的展開與收起一樣),無權訪問該語法 糖定義的人僅僅會看到正常的Java代碼。Chapman說到:

要想實現易於使用的目標還有很多工作要做,但從長遠來看,我發現開發者會很輕松地實現加糖/脫糖 (sugaring/desugaring)的轉換(可以 參考jackpot來 了解實現原理)、不斷嘗試、不斷演進並與同事 和社區分享好的點子。這麼做的好處與語言的演進別無二致。最好的東西會流行起來並形成實際語言演進 的基礎,如 果必要的話還可以隨時去除該方法無法實現的“噪音”。

由於語法糖還要兼顧(非常多)其他的語言特性,因此無法提供完整的閉包支持;比如說BGGA閉包就 有一些特性無法匹配匿名內部類,因此不能通過這種方式實現。話雖如此,這種想 法卻展示了通過各種 新語法來表示匿名內部類的可行性,類似於BGGA語法或是FCM語法,開發者也可以選擇自己喜歡的語法。 其他的語言特性(如null-safe Elvis operator)可以通過這種方式實現。要想進一步驗證該想法,可以 體驗一下這個NetBeans module(由Chapman開發),這正是他所說的用於 Properties的原型。

結論

在語言的發展過程中總是需要考慮穩定與發展之間的平衡。上面介紹的技術所帶來的好處是他們不會 影響平台或是語言本身。這麼做允許我們犯錯誤,也有益於進行快速激進的試驗。由於開發者能夠自由地 進行試驗,我們看到越來越多的人開始解決常見的樣板代碼“噪音”問題,如匿名內部類語法等,同時將 這些想法以合理的方式組織起來以獲得最大的價值。我們將欣喜地看到開發者使用這些方法將Java平台推 向新的遠方。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved