您好,登錄后才能下訂單哦!
小編給大家分享一下四種Java腳本語言對比的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
在一些Java應(yīng)用的需求中,集成某種腳本語言的支持能夠帶來很大的方便。例如,用戶可能想要編寫腳本程序驅(qū)動應(yīng)用、擴展應(yīng)用,或為了簡化操作而編寫循環(huán)和其他流程控制邏輯。在這些情況下,一種理想的解決方案是在Java應(yīng)用中提供對腳本語言解釋器的支持,讓腳本語言解釋器讀取用戶編寫的腳本并在應(yīng)用提供的類上運行這些腳本。為了實現(xiàn)這個目標(biāo),你可以在Java應(yīng)用所運行的JVM中,運行一個基于Java的腳本語言解釋器。
一些支持庫,例如IBM的Bean Scripting Framework,能夠幫助你把不同的腳本語言集成到Java程序。這些支持框架能夠讓你的Java應(yīng)用在不作大量修改的情況下,運行Tcl、Python和其他語言編寫的腳本。
在Java應(yīng)用中集成了腳本解釋器之后,用戶編寫的腳本能夠直接引用Java應(yīng)用的類,就如這些腳本屬于Java程序的一部分一樣。這種思路既有優(yōu)點也有缺點。其優(yōu)點在于,如果你想要用腳本驅(qū)動的方式對應(yīng)用進行回歸測試,或者想要通過腳本對應(yīng)用進行低級調(diào)用,它能夠帶來很大的方便;其缺點在于,如果用戶的腳本直接操作Java程序的內(nèi)部結(jié)構(gòu)而不是經(jīng)過認可的API,它可能影響Java程序的完整性和應(yīng)用的安全。因此,應(yīng)當(dāng)仔細地規(guī)劃那些允許用戶針對其編寫腳本的API,并聲明程序的其余部分不允許用腳本操作。另外,你還可以對那些不想讓用戶針對其進行腳本編程的類和方法名稱進行模糊處理,只留出那些允許腳本編程的API類和方法名字。這樣,你就能夠有效地降低喜歡冒險的用戶直接用腳本操作受保護的類和方法的可能性。
在Java程序中支持多種腳本語言有著非同尋常的意義,但如果你正在編寫的是一個商業(yè)應(yīng)用,則應(yīng)當(dāng)慎重考慮——盡管你為用戶提供了最完善的功能,但同時也帶來了最多的出錯機會。必須考慮到配置和管理問題,因為至少有一部分的腳本解釋器在定期地進行升級和更新,這樣你就必須花很大的力氣管理各個解釋器的哪些版本適合于Java應(yīng)用的哪些版本。如果用戶為了解決舊腳本解釋器中存在的BUG,對其中某個腳本解釋器進行了升級,你的Java應(yīng)用就會運行在一種未經(jīng)完全測試的配置下。數(shù)天或數(shù)星期之后,用戶也許會發(fā)現(xiàn)由于腳本引擎升級而產(chǎn)生的問題,但他們很可能不會把腳本引擎升級的事情告訴你,這時你就很難再次重復(fù)試驗出用戶報告的錯誤了。
另外,用戶很可能堅持認為你必須為Java應(yīng)用支持的腳本解釋器提供補丁。一些腳本解釋器按照源代碼開放的模式及時進行維護和更新;對于這些腳本解釋器,可能有專家?guī)椭憬鉀Q問題、修補解釋器,或在新的發(fā)行版中引入補丁。這是很重要的,因為腳本解釋器是一個很復(fù)雜的工具,包含大量的代碼,如果沒有專家的支持,對于自己修改腳本解釋器這一令人煩惱的任務(wù),你很可能束手無策。
為了避免出現(xiàn)這種問題,你應(yīng)該對于每一種準備在Java應(yīng)用中提供支持的腳本解釋器進行全面的測試。對于每一種解釋器,確保它能夠順利地處理絕大多數(shù)常見的使用情形,確保它即使在極端苛刻的條件下運行大量的腳本也不會出現(xiàn)大的內(nèi)存漏洞,確保當(dāng)你對Java程序和腳本解釋器進行嚴格的Beta測試時不會出現(xiàn)任何意外的情況。當(dāng)然,這種前期測試需要投入時間和其他資源;但不管怎樣,測試投入總是物有所值的。
二、保持系統(tǒng)簡潔
如果你必須在Java應(yīng)用中提供腳本支持,首先必須選擇一個最符合應(yīng)用要求和用戶基礎(chǔ)的腳本解釋器。選擇合適的解釋器能夠簡化集成解釋器的代碼,減少客戶支持方面的支出,以及提高應(yīng)用的穩(wěn)定性。最困難的問題在于:如果只能選用一種解釋器,應(yīng)該選用哪一種呢?
我比較了幾種腳本解釋器,開始時考慮的腳本語言包括Tcl、Python、Perl、JavaScript和BeanShell。接著,在深入分析之前,我放棄了Perl。為什么呢?因為Perl沒有用Java寫的解釋器。假設(shè)你選擇了一個用本機代碼實現(xiàn)的腳本解釋器,例如Perl,則Java應(yīng)用和腳本代碼之間的交互就不再直接進行;另外,對于每一個你想要支持的操作系統(tǒng),都必須提供一個腳本解釋器的二進制代碼庫。由于許多開發(fā)者選擇Java是因為看中了它的跨平臺可移植性,為了保證Java應(yīng)用有這種優(yōu)點,所以最好選擇一種不依賴于本機代碼的解釋器。和Perl不同,Tcl、Python、JavaScript和BeanShell都有基于Java的解釋器,所以這些語言的代碼可以與Java應(yīng)用在同一個JVM和進程之內(nèi)運行。
基于以上標(biāo)準,參與本文評測的腳本解釋器包括:
Jacl:Tcl的Java實現(xiàn)。
Jython:Python的Java實現(xiàn)。
Rhino:JavaScript的Java實現(xiàn)。
BeanShell:一個用Java編寫的Java源代碼解釋器。
限定了待比較的解釋器種類之后,接下來就可以從各個方面對它們進行比較了。
三、評測之一:可用性
第一個評測項目是可用性。這項評測分析了是否存在某種解釋器不可用的情形。用每一種語言各編寫一個簡單的測試程序,然后分別用相應(yīng)的解釋器運行,結(jié)果發(fā)現(xiàn),所有解釋器都通過了測試,每一種解釋器都能夠穩(wěn)定地工作或能夠方便地與之交互。既然每一種解釋器都值得考慮,那么,有哪些因素可能使開發(fā)者偏愛其中一種呢?
Jacl:如果你想要在Tk腳本代碼中創(chuàng)建用戶界面元素,請訪問Swank project,它把Java的Swing部件封裝到了Tk里面。發(fā)行版不包含Jacl腳本的調(diào)試器。
Jython:支持用Python語法編寫的腳本。Python利用縮進層次表示代碼塊的結(jié)構(gòu),而不是象其他許多語言一樣用花括號或開始-結(jié)束符號表示控制流程。至于這種改變究竟是好事還是壞事,這就要看你和用戶的習(xí)慣了。發(fā)行版不包含Jython腳本的調(diào)試器。
Rhino:許多程序員總是把JavaScript和Web頁面編程關(guān)聯(lián)起來,但這個版本的JavaScript不需要在瀏覽器中運行。在使用過程中,我沒有發(fā)現(xiàn)任何問題。它的發(fā)行版帶有一個簡單但實用的腳本調(diào)試器。
BeanShell:Java程序員很快會對這個源代碼解釋器產(chǎn)生一種親切的感覺。BeanShell的文檔寫得很不錯,但開發(fā)組很小。然而,只有當(dāng)BeanShell的開發(fā)者改變了他們的興趣,卻又沒有其他人填補他們轉(zhuǎn)換興趣后留下的空白時,開發(fā)組太小才會成為一個問題。它的發(fā)行版不包含BeanShell腳本調(diào)試器。
四、評測之二:性能
第二個評測項目是性能。這項測試是要分析各個腳本解釋器執(zhí)行一些簡單程序的速度。本次測試沒有要求解釋器排序大型數(shù)組,也沒有執(zhí)行復(fù)雜的數(shù)學(xué)計算,而是執(zhí)行了一些簡單的、常見的操作,例如循環(huán)、整數(shù)比較,以及分配和初始化大型數(shù)組和二維數(shù)組。測試程序都很簡單,且這些操作都是每一個商業(yè)應(yīng)用或多或少要用到的。另外,本項測試還分析了每一個解釋器初始化和執(zhí)行簡單腳本所需要的內(nèi)存。
為一致起見,測試程序的每一種腳本語言的版本都盡量地相似。測試在一臺Toshiba Tecra 8100筆記本上進行,CPU是700-MHz的Pentium III處理器,RAM是256 MB。調(diào)用JVM時,堆棧大小使用默認值。
為了便于理解和比較腳本程序的執(zhí)行速度,本項評測還在Java 1.3.1下運行了類似功能的Java程序,又在Tcl本機解釋器內(nèi)運行了為Jacl腳本解釋器編寫的Tcl腳本。因此,在下面的表格中,你還可以看到這兩次測試的結(jié)果。
表格一:從1到1000000計數(shù)的for循環(huán):
解釋器類型 時間
-----------------------
Java 10 毫秒
Tcl 1.4 秒
Jacl 140 秒
Jython 1.2 秒
Rhino 5 秒
BeanShell 80 秒
--------------------
表格二:比較整數(shù)是否相等,1000000次:
解釋器類型 時間
-----------------------
Java 10 毫秒
Tcl 2 秒
Jacl 300 秒
Jython 4 秒
Rhino 8 秒
BeanShell 80 秒
--------------------
表格三:分配并初始化100000個元素的數(shù)組:
解釋器類型 時間
-----------------------
Java 10 毫秒
Tcl .5 秒
Jacl 25 秒
Jython 1 秒
Rhino 1.3 秒
BeanShell 22 秒
--------------------
表格四:分配并初始化500 X 500 個元素的數(shù)組:
解釋器類型 時間
--------------------
Java 20 毫秒
Tcl 2 秒
Jacl 45 秒
Jython 1 秒
Rhino 7 秒
BeanShell 18 秒
--------------------
表格五:在JVM內(nèi)初始化解釋器所需要的內(nèi)存:
解釋器類型 內(nèi)存占用
----------------------
Jacl 大約 1 MB
Jython 大約 2 MB
Rhino 大約 1 MB
BeanShell 大約 1 MB
----------------------
本項評測證明Jython具有最好的性能,與其他解釋器拉開了相當(dāng)可觀的差距,Rhino第二,BeanShell稍慢,而Jacl墊底。然而,對于你來說,這些性能數(shù)據(jù)到底能夠產(chǎn)生多大的影響,這與你想要用腳本語言完成的任務(wù)密切相關(guān)。如果腳本函數(shù)中包含大量的迭代操作,那么Jacl或BeanShell可能是令人難以接受的。如果腳本程序重復(fù)執(zhí)行代碼的機會很少,那么這些解釋器在速度上的相對差異就不那么重要了。值得指出的是,Jython看來沒有為聲明二維數(shù)組提供內(nèi)建的直接支持,但這個問題可以通過一個“數(shù)組的數(shù)組”結(jié)構(gòu)解決。
五、評測之三:集成的難易程度
本項評測包含兩個任務(wù)。第一個任務(wù)是比較對各種腳本語言解釋器進行實例化時需要多少代碼;第二個任務(wù)是編寫一個完成如下操作的腳本:實例化一個Java JFrame,放入一個JTree,調(diào)整大小并顯示出JFrame。盡管這些任務(wù)都很簡單,但由此我們可以看出開始使用一個解釋器要做多少工作,還可以看出為解釋器編寫的腳本代碼在調(diào)用Java類時到底是什么樣子。
■ Jacl
要把Jacl集成到Java應(yīng)用,首先要把Jacl的Jar文件加入到Java的CLASSPATH,然后在執(zhí)行腳本之前,創(chuàng)建Jacl解釋器的實例。下面是創(chuàng)建Jacl解釋器實例的代碼:
import tcl.lang.*;public class SimpleEmbedded { public static void main(String args[]) { try { Interp interp = new Interp(); } catch (Exception e) { }}
下面的Jacl腳本代碼顯示了如何創(chuàng)建一個JTree,把它放入JFrame,調(diào)整大小并顯示JFrame:
package require javaset env(TCL_CLASSPATH) set mid [java::new javax.swing.JTree]set f [java::new javax.swing.JFrame]$f setSize 200 200set layout [java::new java.awt.BorderLayout]$f setLayout $layout$f add $mid $f show
■ Jython
要把Jython集成到Java應(yīng)用,首先要把Jython的Jar文件加入到Java的CLASSPATH,然后在執(zhí)行腳本之前,創(chuàng)建一個Jython解釋器的實例。完成這個任務(wù)的代碼很簡單:
import org.python.util.PythonInterpreter;import org.python.core.*;public class SimpleEmbedded { public static void main(String []args) throws PyException { PythonInterpreter interp = new PythonInterpreter(); }}
下面的Jython腳本代碼顯示了如何創(chuàng)建JTree,把它放入JFrame,然后顯示出JFrame。下面的代碼不包含調(diào)整大小的操作:
from pawt import swingimport java, sysframe = swing.JFrame('Jython example', visible=1)tree = swing.JTree()frame.contentPane.add(tree)frame.pack()
■ Rhino
和其他解釋器一樣,集成Rhino時首先要把Rhino的Jar文件加入到Java的CLASSPATH,然后在執(zhí)行腳本之前,創(chuàng)建Rhino解釋器的實例:
import org.mozilla.javascript.*;import org.mozilla.javascript.tools.ToolErrorReporter;public class SimpleEmbedded { public static void main(String args[]) { Context cx = Context.enter(); }}
下面簡單的Rhino腳本顯示了如何創(chuàng)建JTree,把它放入JFrame,調(diào)整大小并顯示出JFrame:
importPackage(java.awt);importPackage(Packages.javax.swing);frame = new Frame("JavaScript");frame.setSize(new Dimension(200,200)); frame.setLayout(new BorderLayout());t = new JTree();frame.add(t, BorderLayout.CENTER);frame.pack();frame.show();
■ BeanShell
集成BeanShell也和集成其他解釋器一樣簡單。先把BeanShell的Jar文件加入到Java的CLASSPATH,然后在執(zhí)行腳本代碼之前創(chuàng)建一個BeanShell解釋器的實例:
import bsh.Interpreter;public class SimpleEmbedded { public static void main(String []args) throws bsh.EvalError { Interpreter i = new Interpreter(); }}
下面的BeanShell腳本代碼顯示了如何創(chuàng)建一個JTree,把它放入JFrame,調(diào)整大小并顯示出JFrame。代碼很簡單,且具有熟悉的Java風(fēng)格:
frame = new JFrame();tree = new JTree();frame.getContentPane().add(tree);frame.pack();frame.show();
從上面的說明可以看出,在Java應(yīng)用中集成任何一種解釋器都是很容易的。同時,只要你掌握了腳本語言的語法,就能夠高效地編寫出腳本程序。前面幾個簡單的例子顯示出,用BeanShell和JavaScript編寫的腳本在格式上與Java最相似,而Jacl和Jython則顯得有些不同,但Jacl和Jython腳本也不是難以理解的。正如上面為各個腳本解釋器編寫的腳本所顯示的,在腳本代碼和Java應(yīng)用的類之間不存在任何防火墻。因此必須注意:腳本代碼直接在Java應(yīng)用的類的基礎(chǔ)上運行。應(yīng)當(dāng)確信這就是你想要的效果。如果你想要在運行時對應(yīng)用的某些部分進行保護,避免腳本代碼訪問某些部分,就應(yīng)當(dāng)采取對非公開的代碼進行模糊處理之類的措施,避免人們直接對不公開的API進行編程。
六、評測之四:支持和許可問題
盡管集成腳本解釋器賦予Java應(yīng)用額外的能力,但同時它也使得Java應(yīng)用依賴于那些腳本庫。在確定選用某一種腳本解釋器之前,考慮一下將來的某一天你必須修改被集成的代碼的機會。如果腳本解釋器的開發(fā)者很少更新或升級解釋器,這不是一個好的跡象。它或者意味著當(dāng)時的解釋器實現(xiàn)代碼已經(jīng)很完美,或者負責(zé)這些代碼的開發(fā)者已經(jīng)轉(zhuǎn)移到其他軟件項目上。至于哪一種情況的可能性比較大,答案非常明顯。
另外,還有必要看看實現(xiàn)解釋器需要多少源代碼。試圖掌握解釋器的每一行代碼并對它進行擴展或改進是不切實際的,因為解釋器的代碼規(guī)模實在太大了。盡管如此,了解解釋器的規(guī)模仍是必要的,因為在某些時候,你可能需要修改解釋器的源代碼,也可能為了掌握解釋器的具體工作原理而需要對解釋器代碼作比較深入的了解。
下面就來看看每一種解釋器的代碼庫支持問題。
Jacl
Jacl有一個活躍的支持和開發(fā)組。盡管開發(fā)網(wǎng)站上的下載鏈接指向了一個數(shù)年前的發(fā)行版,但新的版本可通過CVS版本控制系統(tǒng)找到。Jacl包含約37000行Java代碼。
Jython
Jython的支持、維護和更新看起來都很活躍。Jython大約包含55000行Java代碼。
Rhino
Rhino的更新和發(fā)行都比較頻繁,它大約包含44000行Java代碼。
BeanShell
BeanShell也定期地進行更新,它大約包含25000行Java代碼,另外還有不少BeanShell腳本提供。
可以看出,所有這些解釋器都很龐大。如果你能夠依賴于解釋器的開發(fā)和支持組織提供的改進和BUG補丁,你自己的麻煩就會少一些。在選擇一個解釋器之前,不妨看看解釋器升級和發(fā)行是否很頻繁。也許你可以與某個開發(fā)者取得聯(lián)系,了解他們的長遠計劃以及BUG修正過程。
這些解釋器都是可以免費下載的。然而,如果要把它們嵌入到商業(yè)應(yīng)用之中,它們的許可規(guī)則又是怎樣的呢?好在對于所有這些解釋器來說,軟件許可都不存在什么問題。閱讀Jacl、Jython、JavaScript和BeanShell的許可協(xié)議可以發(fā)現(xiàn),用戶必須遵從GNU LGP或等價的許可。這就意味著,即使你的Java應(yīng)用不是免費的,仍舊可以在發(fā)布應(yīng)用時帶上腳本解釋器。但是,你不能刪除源代碼文件和腳本文件中的版權(quán)信息,而且還要明確地告訴用戶,與Java應(yīng)用捆綁在一起的腳本解釋器屬于其他人所有。
七、結(jié)束語
如果你打算在Java應(yīng)用中集成腳本編程支持,我建議你只選用一個腳本解釋器。在你的產(chǎn)品中,每次額外增加一種腳本支持都會帶來相應(yīng)的代價,因此應(yīng)該避免在Java應(yīng)用中集成一種以上的腳本解釋器。為Java應(yīng)用添加腳本支持時,選用基于Java的解釋器而不是Perl之類的本機解釋器能夠簡化以后的工作,能夠使你的產(chǎn)品具有更好的可移植性,并為Java程序和解釋器的集成工作帶來方便。
如果客戶想要用某種特定的腳本語言來定制你的產(chǎn)品,務(wù)必認真地檢查一下如果集成了支持該語言的腳本解釋器是否會出現(xiàn)問題。如果你不必局限于某種特定的腳本語言,則應(yīng)當(dāng)從多個不同的角度對解釋器進行比較,看看哪一個更適合Java應(yīng)用所面臨的主要任務(wù)。
例如,與其他解釋器相比,Jacl的發(fā)展速度看起來特別慢,但如果你必須使用Tcl腳本,使用Jacl解釋器仍舊是值得的。如果你要把一個應(yīng)用從Tcl/Tk移植到Java,Jacl使得新的Java應(yīng)用能夠運行原來的Tcl腳本,這種能力的價值可能超越其他方面的不足。另外,Tcl屬于流行的編程語言,很多開發(fā)者已經(jīng)熟悉它,而且關(guān)于Tcl編程的書也容易買到。
如果你喜歡Java風(fēng)格的腳本代碼,并且力求減少集成過程中的麻煩,BeanShell看來很不錯。它的不足之處是,BeanShell語法和編程方面的用戶指南僅僅局限于發(fā)行版所包含的內(nèi)容,而且BeanShell與其他一些腳本解釋器相比運行速度較慢。另一方面,我覺得BeanShell比較容易使用。BeanShell的庫組織得很好,從而簡化了集成工作。如果你選擇腳本解釋器時性能不是關(guān)鍵的考慮因素,那么你可以考慮BeanShell。
Rhino運行速度明顯比BeanShell快,而且它也同樣支持Java風(fēng)格的腳本。另外,它看起來具有較高的開發(fā)質(zhì)量和支持服務(wù),有關(guān)JavaScript語法和編程的書也很容易找到。如果你對性能、Java風(fēng)格的語法和強大的支持服務(wù)有著差不多平衡的需求, Rhino無疑是推薦考慮的。
以上是“四種Java腳本語言對比的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。