aviator本來是一個輕量級、高性能的基于JVM的表達式引擎。不過從5.0.0版本開始,aviator升級成為了aviatorScript,成為一個高性能、輕量級寄宿于 JVM (包括 Android 平臺)之上的腳本語言。
根據官網的介紹,aviator支持的主要特性:
支持數字、字符串、正則表達式、布爾值、正則表達式等基本類型,完整支持所有 Java 運算符及優先級等。
函數是一等公民,支持閉包和函數式編程
內置 bigint/decimal類型用于大整數和高精度運算,支持運算符重載得以讓這些類型使用普通的算術運算符 +-*/ 參與運算。
完整的腳本語法支持,包括多行數據、條件語句、循環語句、詞法作用域和異常處理等。
函數式編程結合 Sequence 抽象,便捷處理任何集合。
輕量化的模塊系統。
多種方式,方便地調用 Java 方法,完整支持 Java 腳本 API(方便從 Java 調用腳本)。
豐富的定制選項,可作為安全的語言沙箱和全功能語言使用。
輕量化,高性能,ASM 模式下通過直接將腳本翻譯成 JVM 字節碼,解釋模式可運行于 Android 等非標 Java 平臺。
使用場景包括:
規則判斷及規則引擎
公式計算
動態腳本控制
集合數據 ELT 等
aviator基本使用
基本表達式
要使用aviator,只需要添加相應依賴:
?
???? com.googlecode.aviator ????aviator ????5.3.3
?
然后就可以進行表達式求值了:
?
//?返回值為16 Long?r?=?(Long)?AviatorEvaluator.execute("2?*?(3?+?5)");
?
為了提升性能,往往先編譯表達式,然后可以反復執行,進行表達式求值:
?
Expression?expression?=?AviatorEvaluator.compile("2?*?(3?+?5)"); Long?r?=?(Long)?expression.execute();
?
aviator支持數字、字符串、布爾值等基本數據類型,數字類型值都當作long或double類型處理。關注工眾號:碼猿技術專欄,回復關鍵詞:1111 ?獲取阿里內部java性能調優手冊!所以上面例子的求值結果是Long。
aviator表達式支持大部分的運算操作符,如常用的算術運算操作符(+、-、*、/、%)、邏輯運算操作符(&&、||、!)、比較運算操作符(>、>=、==、!=、<、<=)、位運算操作符(&、|、^、<<、>>)和優先級操作符,還支持三元操作表達(?:)、正則表達式(=~)。
一些例子:
?
??//?返回?hello?world ????String?r?=?(String)?AviatorEvaluator.execute("'hello'?+?'?world'"); ???? ????//?返回?true ????Boolean?r?=?(Boolean)?AviatorEvaluator.execute("100?>?80?&&?30?40"); ???? ????//?三元表達式,返回?30 ????Long?r?=?(Long)?AviatorEvaluator.execute("100?>?80???30?:?40"); ???? ????//?正則表達式,正則表達式放在//之間,返回?true ????Boolean?r?=?(Boolean)?AviatorEvaluator.execute("'hello'?=~?/[\w]+/");
?
表達式變量
跟其他表達式引擎一樣,aviator也是支持表達式求值時傳入參數的:
?
Long?a?=?12L; Boolean?r?=?(Boolean)?AviatorEvaluator.exec("a?>?10",?a);
?
參數也可以是一個列表,如下:
?
List?a?=?new?ArrayList<>(); a.add(12L); a.add(20L); Boolean?r?=?(Boolean)?AviatorEvaluator.exec("a[0]?>?10",?a);
?
也可以是一個對象:
?
public?static?class?Person?{ ????????private?String?name; ????????private?Integer?age; ????} Person?a?=?new?Person("movee",?25); Boolean?r?=?(Boolean)?AviatorEvaluator.exec("a.age?>?10",?a);
?
跟一般地,aviator會將參數放到一個map中
?
Map?env?=?new?HashMap<>(); env.put("person",?new?Person("movee",?25)); env.put("a",?20L); Object?result?=?AviatorEvaluator.execute("person.name",?env);
?
這樣一來,aviator可以非常方便的從json字符串中提取子json字符串
?
String?jsonStr?=?""" ????????{ ????????????"a":?{ ????????????????"b":?[ ????????????????????????{ ????????????????????????????"x":?3 ????????????????????????}, ????????????????????????{ ????????????????????????????"x":?4 ????????????????????????} ????????????????????] ????????????} ????????} ????????"""; ????JSONObject?jsonObj?=?new?JSONObject(jsonStr); ????//?結果返回?3 ????Object?value?=?AviatorEvaluator.execute("a.b[0]['x']",?jsonObj.toMap());
?
使用函數
aviator已經提供了很多開箱即用的函數了:
?
//?返回4 ????Long?r?=?(Long)?AviatorEvaluator.execute("math.round(4.3)"); ???? ????//?返回5 ????Long?r?=?(Long)?AviatorEvaluator.execute("string.length('hello')"); ???? ????//?返回一個ArrayList:[1,2,3] ????Object?r?=?AviatorEvaluator.execute("seq.list(1,2,3)");
?
更詳細的內置函數列表請參考:aviator函數庫列表
我們也可以自定義一個java函數,自己編寫一個類,繼承aviator的AbstractFunction類,然后實現相應的方法即可:
?
public?class?AddFunction?extends?AbstractFunction?{ ????????/** ?????????*?函數實現的功能 ?????????*?@param?env?參數 ?????????*?@param?arg1?函數的第一個參數 ?????????*?@param?arg2?函數的第二個參數 ?????????*?@return?返回值 ?????????*/ ????????@Override ????????public?AviatorObject?call(Map?env,?AviatorObject?arg1,?AviatorObject?arg2)?{ ????????????long?num1?=?FunctionUtils.getNumberValue(arg1,?env).longValue(); ????????????long?num2?=?FunctionUtils.getNumberValue(arg2,?env).longValue(); ????????????return?AviatorLong.valueOf(num1+num2); ????????} ????????/** ?????????*?注冊到aviator的名字 ?????????*?@return?函數名字 ?????????*/ ????????@Override ????????public?String?getName()?{ ????????????return?"add"; ????????} ????}
?
然后就可以注冊到aviator中,像使用內置函數一樣使用自定義函數:
?
//?注冊 ????AviatorEvaluator.addFunction(new?AddFunction()); ???? ????//?使用 ????long?sum?=?(Long)?AviatorEvaluator.getInstance().execute("add(3,4)");
?
aviatorScript腳本
aviator已經升級為一個腳本語言,所以不僅僅能進行表達式求值,還可以執行腳本程序。
?
//?返回1 ????Object?r?=?AviatorEvaluator.execute("if?(true)?{?return?1;?}?else?{?return?2;?}");
?
aviatorScript腳本一般放到獨立的腳本文件中,文件名后綴一般為.av
例如,我們編寫一個hello.av腳本文件,內容為:
?
if?(a?>?10)?{ ????return?10; }?else?{ ????return?a; }
?
然后就可以執行該腳本文件,并傳入參數a的值:
?
Map?env?=?new?HashMap<>(); ????env.put("a",?30); ????Expression?exp?=?AviatorEvaluator.getInstance().compileScript("./hello.av",?true); ????Object?result?=?exp.execute(env);
?
評論
查看更多