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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

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

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

  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.”

“有生以來第一次掙了很多錢,于是,我想回家陪陪我媽一起過圣誕節”

一、基礎介紹

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

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

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


我們先來個例子感覺一下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進行JavaFX開發會快很多。

二、在哪里使用JS

Shell腳本

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

#!/usr/bin/env jjs 

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

向jjs傳遞程序參數,需要加“—”前綴。因此舉例來說,你可以這樣調用:

./hello-script.js – Joe

如果沒有“—”前綴,參數會被解釋為文件名。

向Java傳遞數據或者從Java傳出數據

正如上文所說的那樣,你可以從Java代碼直接調用JavaScript;只需獲取一個引擎對象并調用它的“eval”方法。你可以將數據作為字符串顯式傳遞……

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

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

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

JavaScript eval的求值結果將會從引擎的“eval”方法返回:

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

在Nashorn中使用Java類

前面已經提到,Nashorn最強大的功能之一源于在JavaScript中調用Java類。你不僅能夠訪問類并創建實例,你還可以繼承他們,調用他們的靜態方法,幾乎可以做任何你能在Java中做的事。

作為一個例子,讓我們看下來龍去脈。JavaScript沒有任何語言特性是面向并發的,所有常見的運行時環境都是單線程的,或者至少沒有任何共享狀態。有趣的是,在Nashorn環境中,JavaScript確實可以并發運行,并且有共享狀態,就像在Java中一樣:

// 訪問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();

請注意,從Nashorn訪問類的規范做法是使用Java.type,并且可以使用Java.extend擴展一個類。

Nashorn JavaScript特有的方言

正如簡介部分所提到的那樣,Nashorn支持的JavaScript實現了ECMAScript 5.1版本及一些擴展。我并不建議使用這些擴展,因為它們既不是Java,也不是JavaScript,兩類開發人員都會覺得它不正常。另一方面,有兩個擴展在整個Oracle文檔中被大量使用,因此,我們應該了解它們。首先,讓我們為了解第一個擴展做些準備。正如前文所述,開發人員可以使用Java.extend從JavaScript中擴展一個Java類。如果需要繼承一個抽象Java類或者實現一個接口,那么可以使用一種更簡便的語法。在這種情況下,開發人員實際上可以調用抽象類或接口的構造函數,并傳入一個描述方法實現的JavaScript對象常量。這種常量不過是name/value對,你可能了解JSON格式,這與那個類似。這使我們可以像下面這樣實現Runnable接口:

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

在這個例子中,一個對象常量指定了run方法的實現,我們實際上是用它調用了Runnable的構造函數。注意,這是Nashorn的實現提供給我們的一種方式,否則,我們無法在JavaScript這樣做。

示例代碼已經與我們在Java中以匿名內部類實現接口的方式類似了,但還不完全一樣。這將我們帶到了第一個擴展,它允許開發人員在調用構造函數時在右括號“)”后面傳遞最后一個參數。這種做法的代碼如下:

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

……它實現了完全相同的功能,但更像Java。

第二個常用的擴展一種函數的簡便寫法,它允許刪除單行函數方法體中的兩個花括號以及return語句。這樣,上一節中的例子:

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

可以表達的更簡潔一些:

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

Avatar.js

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

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

讓我們來看一個JavaScript的小例子,它是我根據Node網站上的例子改寫而來:

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

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

//監聽localhost,端口1337
//并提供回調函數handleRequest
//這里體現了其非阻塞/異步特性
http.createServer(handleRequest).listen(1337, '127.0.0.1'); 

//記錄到控制臺,確保我們在沿著正確的方向前進
console.log('Get your hello at http://127.0.0.1:1337/');

要運行這段代碼,需要安裝Node,然后將上述JavaScript代碼保存到一個文件中。最后,將該文件作為一個參數調用Node。

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

令人遺憾的是,在寫這篇文章的時候,還沒有一個Avatar.js的二進制分發包。有一個自述文件說明了如何從源代碼進行構建,但是如果真沒有那么多時間從頭開始構建,那么也可以從這里下載二進制文件而不是自行構建。兩種方式都可以,但為了更快的得到結果,我建議選擇第二種方式。

一旦創建了二進制文件并放進了lib文件夾,就可以使用下面這樣的語句調用Avatar.js框架:

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

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

讓我們再問一次,這為什么有用?Oracle的專家(幻燈片10)指出了該庫的幾個適用場景。我對其中的兩點持大致相同的看法,即:

有一個Node應用程序,并希望使用某個Java庫作為Node API的補充
希望切換到JavaScript和Node API,但需要將遺留的Java代碼部分或全部嵌入

兩個應用場景都可以通過使用Avatar.js并從JavaScript代碼中調用任何需要的Java類來實現。我們已經看到,Nashorn支持這種做法。

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

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

讓我們看一個Web服務示例,它計算某個數量的百分之幾是多少。首先,需要有一個函數執行實際的計算:

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沒有類型聲明,除此之外,上述代碼與我針對該任務編寫的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函數就可以完成代碼。替換后的代碼如下:

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

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

我們又使用了Node核心模塊來處理請求URL,從中解析出查詢參數amount和percentage。

當啟動服務器(如前所述)并使用瀏覽器發出下面這樣一個請求時,

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

就會得到正確的結果“7567230000000000006600158.73”。這在單純使用JavaScript的“number”類型時是不可能。

當你決定將現有的JEE應用程序遷移到JavaScript和Node時,第二個應用場景就有意義了。在這種情況下,你很容易就可以從JavaScript代碼內訪問現有的所有服務。另一個相關的應用場景是,在使用JavaScript和Node構建新的服務器功能時,仍然可以受益于現有的JEE服務。

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

小結

Nashorn項目增強了JDK 6中原有的Rhino實現,極大地提升了運行時間較長的應用程序的性能,例如用在Web服務器中的時候。Nashorn將Java與JavaScript集成,甚至還考慮了JDK 8的新Lambda表達式。Avatar.js帶來了真正的創新,它基于這些特性構建,并提供了企業級Java與JavaScript代碼的集成,同時在很大程度上與JavaScript服務器端編程事實上的標準兼容。

完整實例以及用于Mac OS X的Avatar.js二進制文件可以從Github上下載。

參考鏈接:

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

圖片來源:八惡人(movie)

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。