日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

Java 8新特性之 Nashorn(八恶人-6)

發(fā)布時(shí)間:2024/8/24 综合教程 29 生活家
生活随笔 收集整理的這篇文章主要介紹了 Java 8新特性之 Nashorn(八恶人-6) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  Joe Gage 蓋奇·喬

“First time in my life I made a pretty penny.And, figured I'd come home and spend time with my mothr for Christmas.”

“有生以來(lái)第一次掙了很多錢,于是,我想回家陪陪我媽一起過(guò)圣誕節(jié)”

一、基礎(chǔ)介紹

從JDK 6開(kāi)始,Java就已經(jīng)捆綁了JavaScript引擎,該引擎基于Mozilla的Rhino。該特性允許開(kāi)發(fā)人員將JavaScript代碼嵌入到Java中,甚至從嵌入的JavaScript中調(diào)用Java。此外,它還提供了使用jrunscript從命令行運(yùn)行JavaScript的能力。如果不需要非常好的性能,并且可以接受ECMAScript 3有限的功能集的話,那它相當(dāng)不錯(cuò)了。

從JDK 8開(kāi)始,Nashorn取代Rhino成為Java的嵌入式JavaScript引擎。Nashorn完全支持ECMAScript 5.1規(guī)范以及一些擴(kuò)展。它使用基于JSR 292的新語(yǔ)言特性,其中包含在JDK 7中引入的invokedynamic,將JavaScript編譯成Java字節(jié)碼。

與先前的Rhino實(shí)現(xiàn)相比,這帶來(lái)了2到10倍的性能提升,雖然它仍然比Chrome和Node.js中的V8引擎要差一些。


我們先來(lái)個(gè)例子感覺(jué)一下java中使用JavaScript:

        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName( "JavaScript" );

        System.out.println( engine.getClass().getName() );
        try {
            System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );
        }catch (javax.script.ScriptException e){
            e.printStackTrace();
        }

輸出如下:

dk.nashorn.api.scripting.NashornScriptEngine
Result: 2

與Java相比,使用JavaScript進(jìn)行JavaFX開(kāi)發(fā)會(huì)快很多。

二、在哪里使用JS

Shell腳本

Nashorn引擎可以使用jjs命令從命令行調(diào)用。你可以不帶任何參數(shù)調(diào)用它,這會(huì)將你帶入一個(gè)交互模式,或者你可以傳遞一個(gè)希望執(zhí)行的JavaScript文件名,或者你可以用它作為shell腳本的替代,像這樣:

#!/usr/bin/env jjs 

var name = $ARG[0]; 
print(name ? "Hello, ${name}!" : "Hello, world!");

向jjs傳遞程序參數(shù),需要加“—”前綴。因此舉例來(lái)說(shuō),你可以這樣調(diào)用:

./hello-script.js – Joe

如果沒(méi)有“—”前綴,參數(shù)會(huì)被解釋為文件名。

向Java傳遞數(shù)據(jù)或者從Java傳出數(shù)據(jù)

正如上文所說(shuō)的那樣,你可以從Java代碼直接調(diào)用JavaScript;只需獲取一個(gè)引擎對(duì)象并調(diào)用它的“eval”方法。你可以將數(shù)據(jù)作為字符串顯式傳遞……

ScriptEngineManager scriptEngineManager = 
      new ScriptEngineManager(); 
ScriptEngine nashorn = 
      scriptEngineManager.getEngineByName("nashorn"); 
String name = "Olli"; 
nashorn.eval("print('" + name + "')");

……或者你可以在Java中傳遞綁定,它們是可以從JavaScript引擎內(nèi)部訪問(wèn)的全局變量:

int valueIn = 10; 
SimpleBindings simpleBindings = new SimpleBindings(); 
simpleBindings.put("globalValue", valueIn); 
nashorn.eval("print (globalValue)", simpleBindings);

JavaScript eval的求值結(jié)果將會(huì)從引擎的“eval”方法返回:

Integer result = (Integer) nashorn.eval("1 + 2"); 
assert(result == 3);

在Nashorn中使用Java類

前面已經(jīng)提到,Nashorn最強(qiáng)大的功能之一源于在JavaScript中調(diào)用Java類。你不僅能夠訪問(wèn)類并創(chuàng)建實(shí)例,你還可以繼承他們,調(diào)用他們的靜態(tài)方法,幾乎可以做任何你能在Java中做的事。

作為一個(gè)例子,讓我們看下來(lái)龍去脈。JavaScript沒(méi)有任何語(yǔ)言特性是面向并發(fā)的,所有常見(jiàn)的運(yùn)行時(shí)環(huán)境都是單線程的,或者至少?zèng)]有任何共享狀態(tài)。有趣的是,在Nashorn環(huán)境中,JavaScript確實(shí)可以并發(fā)運(yùn)行,并且有共享狀態(tài),就像在Java中一樣:

// 訪問(wèn)Java類Thread 
var Thread = Java.type("java.lang.Thread"); 

// 帶有run方法的子類
var MyThread = Java.extend(Thread, { 
    run: function() { 
        print("Run in separate thread"); 
    } 
}); 
var th = new MyThread(); 
th.start(); 
th.join();

請(qǐng)注意,從Nashorn訪問(wèn)類的規(guī)范做法是使用Java.type,并且可以使用Java.extend擴(kuò)展一個(gè)類。

Nashorn JavaScript特有的方言

正如簡(jiǎn)介部分所提到的那樣,Nashorn支持的JavaScript實(shí)現(xiàn)了ECMAScript 5.1版本及一些擴(kuò)展。我并不建議使用這些擴(kuò)展,因?yàn)樗鼈兗炔皇荍ava,也不是JavaScript,兩類開(kāi)發(fā)人員都會(huì)覺(jué)得它不正常。另一方面,有兩個(gè)擴(kuò)展在整個(gè)Oracle文檔中被大量使用,因此,我們應(yīng)該了解它們。首先,讓我們?yōu)榱私獾谝粋€(gè)擴(kuò)展做些準(zhǔn)備。正如前文所述,開(kāi)發(fā)人員可以使用Java.extend從JavaScript中擴(kuò)展一個(gè)Java類。如果需要繼承一個(gè)抽象Java類或者實(shí)現(xiàn)一個(gè)接口,那么可以使用一種更簡(jiǎn)便的語(yǔ)法。在這種情況下,開(kāi)發(fā)人員實(shí)際上可以調(diào)用抽象類或接口的構(gòu)造函數(shù),并傳入一個(gè)描述方法實(shí)現(xiàn)的JavaScript對(duì)象常量。這種常量不過(guò)是name/value對(duì),你可能了解JSON格式,這與那個(gè)類似。這使我們可以像下面這樣實(shí)現(xiàn)Runnable接口:

var r = new java.lang.Runnable({
    run: function() {
        print("running...
");
    }
});

在這個(gè)例子中,一個(gè)對(duì)象常量指定了run方法的實(shí)現(xiàn),我們實(shí)際上是用它調(diào)用了Runnable的構(gòu)造函數(shù)。注意,這是Nashorn的實(shí)現(xiàn)提供給我們的一種方式,否則,我們無(wú)法在JavaScript這樣做。

示例代碼已經(jīng)與我們?cè)贘ava中以匿名內(nèi)部類實(shí)現(xiàn)接口的方式類似了,但還不完全一樣。這將我們帶到了第一個(gè)擴(kuò)展,它允許開(kāi)發(fā)人員在調(diào)用構(gòu)造函數(shù)時(shí)在右括號(hào)“)”后面?zhèn)鬟f最后一個(gè)參數(shù)。這種做法的代碼如下:

var r = new java.lang.Runnable() {
    run: function() {
       print("running...
");
    }
};

……它實(shí)現(xiàn)了完全相同的功能,但更像Java。

第二個(gè)常用的擴(kuò)展一種函數(shù)的簡(jiǎn)便寫(xiě)法,它允許刪除單行函數(shù)方法體中的兩個(gè)花括號(hào)以及return語(yǔ)句。這樣,上一節(jié)中的例子:

list.forEach(function(el) { print(el) } );

可以表達(dá)的更簡(jiǎn)潔一些:

list.forEach(function(el) print(el));

Avatar.js

我們已經(jīng)看到,有了Nashorn,我們就有了一個(gè)嵌入到Java的優(yōu)秀的JavaScript引擎。我們也已經(jīng)看到,我們可以從Nashorn訪問(wèn)任意Java類。Avatar.js更進(jìn)一步,它“為Java平臺(tái)帶來(lái)了Node編程模型、API和模塊生態(tài)系統(tǒng)”。要了解這意味著什么以及它為什么令人振奮,我們首先必須了解Node是什么。從根本上說(shuō),Node是將Chrome的V8 JavaScript引擎剝離出來(lái),使它可以從命令行運(yùn)行,而不再需要瀏覽器。這樣,JavaScript就不是只能在瀏覽器中運(yùn)行了,而且可以在服務(wù)器端運(yùn)行。在服務(wù)器端以任何有意義的方式運(yùn)行JavaScript都至少需要訪問(wèn)文件系統(tǒng)和網(wǎng)絡(luò)。為了做到這一點(diǎn),Node內(nèi)嵌了一個(gè)名為libnv的庫(kù),以異步方式實(shí)現(xiàn)該項(xiàng)功能。實(shí)際上,這意味著操作系統(tǒng)調(diào)用永遠(yuǎn)不會(huì)阻塞,即使它過(guò)一段時(shí)間才能返回。開(kāi)發(fā)人員需要提供一個(gè)回調(diào)函數(shù)代替阻塞。該函數(shù)會(huì)在調(diào)用完成時(shí)立即觸發(fā),如果有任何結(jié)果就返回。

有若干公司都在重要的應(yīng)用程序中使用了Node,其中包括Walmart和Paypal。

讓我們來(lái)看一個(gè)JavaScript的小例子,它是我根據(jù)Node網(wǎng)站上的例子改寫(xiě)而來(lái):

//加載“http”模塊(這是阻塞的)來(lái)處理http請(qǐng)求
var http = require('http'); 

//當(dāng)有請(qǐng)求時(shí),返回“Hello,World
”
function handleRequest(req, res) { 
  res.writeHead(200, {'Content-Type': 'text/plain'}); 
  res.end('Hello, World
'); 
} 

//監(jiān)聽(tīng)localhost,端口1337
//并提供回調(diào)函數(shù)handleRequest
//這里體現(xiàn)了其非阻塞/異步特性
http.createServer(handleRequest).listen(1337, '127.0.0.1'); 

//記錄到控制臺(tái),確保我們?cè)谘刂_的方向前進(jìn)
console.log('Get your hello at http://127.0.0.1:1337/');

要運(yùn)行這段代碼,需要安裝Node,然后將上述JavaScript代碼保存到一個(gè)文件中。最后,將該文件作為一個(gè)參數(shù)調(diào)用Node。

將libuv綁定到Java類,并使JavaScript可以訪問(wèn)它們,Avatar.js旨在以這種方式提供與Node相同的核心API。雖然這可能聽(tīng)上去很繁瑣,但這種方法很有效。Avatar.js支持許多Node模塊。對(duì)Node主流Web框架“express”的支持表明,這種方式確實(shí)適用于許多現(xiàn)有的項(xiàng)目。

令人遺憾的是,在寫(xiě)這篇文章的時(shí)候,還沒(méi)有一個(gè)Avatar.js的二進(jìn)制分發(fā)包。有一個(gè)自述文件說(shuō)明了如何從源代碼進(jìn)行構(gòu)建,但是如果真沒(méi)有那么多時(shí)間從頭開(kāi)始構(gòu)建,那么也可以從這里下載二進(jìn)制文件而不是自行構(gòu)建。兩種方式都可以,但為了更快的得到結(jié)果,我建議選擇第二種方式。

一旦創(chuàng)建了二進(jìn)制文件并放進(jìn)了lib文件夾,就可以使用下面這樣的語(yǔ)句調(diào)用Avatar.js框架:

java -Djava.library.path=lib -jar lib/avatar-js.jar helloWorld.js

假設(shè)演示服務(wù)器(上述代碼)保存到了一個(gè)名為“helloWorld.js”的文件中。

讓我們?cè)賳?wèn)一次,這為什么有用?Oracle的專家(幻燈片10)指出了該庫(kù)的幾個(gè)適用場(chǎng)景。我對(duì)其中的兩點(diǎn)持大致相同的看法,即:

有一個(gè)Node應(yīng)用程序,并希望使用某個(gè)Java庫(kù)作為Node API的補(bǔ)充
希望切換到JavaScript和Node API,但需要將遺留的Java代碼部分或全部嵌入

兩個(gè)應(yīng)用場(chǎng)景都可以通過(guò)使用Avatar.js并從JavaScript代碼中調(diào)用任何需要的Java類來(lái)實(shí)現(xiàn)。我們已經(jīng)看到,Nashorn支持這種做法。

下面我將舉一個(gè)第一個(gè)應(yīng)用場(chǎng)景的例子。JavaScript目前只有一種表示數(shù)值的類型,名為“number”。這相當(dāng)于Java的“double”精度,并且有同樣的限制。JavaScript的number,像Java的double一樣,并不能表示任意的范圍和精度,比如在計(jì)量貨幣時(shí)。

在Java中,我們可以使用BigDecimal,它正是用于此類情況。但JavaScript沒(méi)有內(nèi)置與此等效的類型,因此,我們就可以直接從JavaScript代碼中訪問(wèn)BigDecimal類,安全地處理貨幣值。

讓我們看一個(gè)Web服務(wù)示例,它計(jì)算某個(gè)數(shù)量的百分之幾是多少。首先,需要有一個(gè)函數(shù)執(zhí)行實(shí)際的計(jì)算:

var BigDecimal = Java.type('java.math.BigDecimal'); 

function calculatePercentage(amount, percentage) { 
    var result = new BigDecimal(amount).multiply( 
     new BigDecimal(percentage)).divide( 
           new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_EVEN); 
    return result.toPlainString(); 
}

JavaScript沒(méi)有類型聲明,除此之外,上述代碼與我針對(duì)該任務(wù)編寫(xiě)的Java代碼非常像:

public static String calculate(String amount, String percentage) { 
    BigDecimal result = new BigDecimal(amount).multiply( 
     new BigDecimal(percentage)).divide( 
          new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_EVEN); 
    return result.toPlainString(); 
}

我們只需要替換上文Node示例中的handleRequest函數(shù)就可以完成代碼。替換后的代碼如下:

//加載工具模塊“url”來(lái)解析url
var url = require('url'); 

function handleRequest(req, res) { 
    // '/calculate' Web服務(wù)地址 
    if (url.parse(req.url).pathname === '/calculate') { 
        var query = url.parse(req.url, true).query;  
       //數(shù)量和百分比作為查詢參數(shù)傳入
        var result = calculatePercentage(query.amount,
                                          query.percentage); 
        res.writeHead(200, {'Content-Type': 'text/plain'}); 
        res.end(result + '
'); 
    } 
}

我們又使用了Node核心模塊來(lái)處理請(qǐng)求URL,從中解析出查詢參數(shù)amount和percentage。

當(dāng)啟動(dòng)服務(wù)器(如前所述)并使用瀏覽器發(fā)出下面這樣一個(gè)請(qǐng)求時(shí),

http://localhost:1337/calculate?
amount=99700000000000000086958613&percentage=7.59

就會(huì)得到正確的結(jié)果“7567230000000000006600158.73”。這在單純使用JavaScript的“number”類型時(shí)是不可能。

當(dāng)你決定將現(xiàn)有的JEE應(yīng)用程序遷移到JavaScript和Node時(shí),第二個(gè)應(yīng)用場(chǎng)景就有意義了。在這種情況下,你很容易就可以從JavaScript代碼內(nèi)訪問(wèn)現(xiàn)有的所有服務(wù)。另一個(gè)相關(guān)的應(yīng)用場(chǎng)景是,在使用JavaScript和Node構(gòu)建新的服務(wù)器功能時(shí),仍然可以受益于現(xiàn)有的JEE服務(wù)。

此外,基于Avatar.js的Avatar項(xiàng)目也朝著相同的方向發(fā)展。該項(xiàng)目的詳細(xì)信息超出了本文的討論范圍,但讀者可以閱讀這份Oracle公告做一個(gè)粗略的了解。該項(xiàng)目的基本思想是,用JavaScript編寫(xiě)應(yīng)用程序,并訪問(wèn)JEE服務(wù)。Avatar項(xiàng)目包含Avatar.js的一個(gè)二進(jìn)制分發(fā)包,但它需要Glassfish用于安裝和開(kāi)發(fā)。

小結(jié)

Nashorn項(xiàng)目增強(qiáng)了JDK 6中原有的Rhino實(shí)現(xiàn),極大地提升了運(yùn)行時(shí)間較長(zhǎng)的應(yīng)用程序的性能,例如用在Web服務(wù)器中的時(shí)候。Nashorn將Java與JavaScript集成,甚至還考慮了JDK 8的新Lambda表達(dá)式。Avatar.js帶來(lái)了真正的創(chuàng)新,它基于這些特性構(gòu)建,并提供了企業(yè)級(jí)Java與JavaScript代碼的集成,同時(shí)在很大程度上與JavaScript服務(wù)器端編程事實(shí)上的標(biāo)準(zhǔn)兼容。

完整實(shí)例以及用于Mac OS X的Avatar.js二進(jìn)制文件可以從Github上下載。

參考鏈接:

http://www.infoq.com/cn/articles/nashorn

圖片來(lái)源:八惡人(movie)

總結(jié)

以上是生活随笔為你收集整理的Java 8新特性之 Nashorn(八恶人-6)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。