點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質(zhì)文章,第一時間送達
1.簡介
Aviator是一個高性能、輕量級的 java 語言實現(xiàn)的表達式求值引擎, 主要用于各種表達式的動態(tài)求值。現(xiàn)在已經(jīng)有很多開源可用的 java 表達式求值引擎,為什么還需要 Avaitor 呢?
Aviator的設計目標是輕量級和高性能,相比于Groovy、JRuby的笨重, Aviator非常小, 加上依賴包也才 537K,不算依賴包的話只有 70K; 當然, Aviator的語法是受限的, 它不是一門完整的語言, 而只是語言的一小部分集合。
其次, Aviator的實現(xiàn)思路與其他輕量級的求值器很不相同, 其他求值器一般都是通過解釋的方式運行, 而Aviator則是直接將表達式編譯成 JVM 字節(jié)碼, 交給 JVM 去執(zhí)行。簡單來說, Aviator的定位是介于 Groovy 這樣的重量級腳本語言和 IKExpression 這樣的輕量級表達式引擎之間。
2.特性
Aviator的特性:
支持絕大多數(shù)運算操作符,包括算術操作符、關系運算符、邏輯操作符、位運算符、正則匹配操作符(=~)、三元表達式(? : );
支持操作符優(yōu)先級和括號強制設定優(yōu)先級;
邏輯運算符支持短路運算;
支持豐富類型,例如nil、整數(shù)和浮點數(shù)、字符串、正則表達式、日期、變量等,支持自動類型轉(zhuǎn)換;
支持傳入變量,支持類似a.b.c的嵌套變量訪問;
內(nèi)置一套強大的常用函數(shù)庫;
可自定義函數(shù),易于擴展;
可重載操作符;
支持大數(shù)運算(BigInteger)和高精度運算(BigDecimal);
性能優(yōu)秀。
Aviator的限制:
3.依賴
Aviator依賴了commons-beanutils, 使用Aviator可以添加下面的maven依賴:
??????com.googlecode.aviator
??????aviator
??????{version}
?
從 3.2.0 版本開始, Aviator 僅支持 JDK 7 及其以上版本。JDK 6 請使用 3.1.1 這個穩(wěn)定版本。
4.使用手冊
執(zhí)行表達式
Aviator的使用都是集中通過com.googlecode.aviator.AviatorEvaluator這個入口類來處理, 最簡單的例子, 執(zhí)行一個計算1+2+3的表達式:
val?result?=?AviatorEvaluator.execute("1+2+3")
println(result)?????//6
如果開啟了 ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL 選項,那么在表達式中出現(xiàn)的浮點數(shù)都將解析為 BigDecimal,這是為了方便一些用戶要求高精度的計算,又不想額外地給浮點數(shù)加上 M 后綴標記為 BigDecimal:
AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL,?true)
多行表達式
從 4.0.0 開始, aviator支持以分號 ; 隔開的多行表達式,對于多行表達式求值的結(jié)果將是最后一個表達式的結(jié)果,例如
val?result?=?AviatorEvaluator.execute("println('hello?world');?1+2+3?;?100-1")
println(result)?
//輸出結(jié)果:
//hello?world
//99
表達式的結(jié)果將是最后一個表達式 100-1,也就是 99,但是中間的表達式也將執(zhí)行,包括打印 hello world。通過在表達式求值過程中加入 println打印,可以方便調(diào)試,也可以通過 Options.TRACE_EVAL來跟蹤執(zhí)行過程,參見后續(xù)章節(jié)。
求值器多實例
AviatorEvaluator是一個全局靜態(tài)實例,但是很多場景下,你可能想為不同的場景提供一個不同的求值器實例,包括不同的選項配置和自定義函數(shù)列表等,那么從 4.0.0開始, Aviator提供了多實例的求值器支持:
val?instance?=?AviatorEvaluator.newInstance
//接下來使用?instance,幾乎跟?AviatorEvaluator?沒有不同,只是換成了實例方法
使用變量
下面的例子演示了怎么向表達式傳入變量值, 表達式中的world是一個變量, 默認為null, 通過傳入Map的變量綁定環(huán)境, 將world設置為“world”。env 的key是變量名, value是變量的值。
val?world?=?"world"
val?env?=?new?util.HashMap[String,Object]()
env.put("world",world)
val?result?=AviatorEvaluator.execute("?'hello?'?+?world?",env)
println(result)????????//??hello?world
'hello ‘是一個Aviator的String, Aviator的String是任何用單引號或者雙引號括起來的字符序列, String可以比較大小(基于unicode順序), 可以參與正則匹配, 可以與任何對象相加, 任何對象與String相加結(jié)果為String。String中也可以有轉(zhuǎn)義字符,如\n、\、’ 等。
AviatorEvaluator.execute("?'a\"b'?")??????????????????//?字符串?a"b
AviatorEvaluator.execute("?\"a\'b\"?")????????????????//?字符串?a'b
AviatorEvaluator.execute("?'hello?'?+?3?")??????????????//?字符串?hello?3
AviatorEvaluator.execute("?'hello?'+?unknow?")?????????//?字符串?hello?null
exec 方法
Aviator 2.2 開始新增加一個exec方法, 可以更方便地傳入變量并執(zhí)行, 而不需要構(gòu)造env這個map了:
val?value?=?"world"
AviatorEvaluator.exec("'hello'?+?value",value)????????//??hello?world
調(diào)用函數(shù)
Aviator 支持函數(shù)調(diào)用, 函數(shù)調(diào)用的風格類似 lua, 下面的例子獲取字符串的長度:
AviatorEvaluator.execute("string.length('hello')")?
string.length(‘hello’)是一個函數(shù)調(diào)用, string.length是一個函數(shù), 'hello’是調(diào)用的參數(shù)。
再用string.substring來截取字符串:
AviatorEvaluator.execute("string.contains(\"test\",?string.substring('hello',?1,?2))")?//?true
通過string.substring(‘hello’, 1, 2)獲取字符串’e’, 然后通過函數(shù)string.contains判斷e是否在’test’中??梢钥吹? 函數(shù)可以嵌套調(diào)用。
自定義函數(shù)
Aviator除了內(nèi)置的函數(shù)之外,還允許用戶自定義函數(shù),只要實現(xiàn)com.googlecode.aviator.runtime.type.AviatorFunction接口, 并注冊到AviatorEvaluator即可使用. AviatorFunction接口十分龐大, 通常來說你并不需要實現(xiàn)所有的方法, 只要根據(jù)你的方法的參數(shù)個數(shù), 繼承AbstractFunction類并override相應方法即可。
object?test?{
??def?main(args:?Array[String]):?Unit?=?{
????AviatorEvaluator.addFunction(new?AddFunction)
????System.out.println(AviatorEvaluator.execute("add(1,?2)"))?//?3.0
????System.out.println(AviatorEvaluator.execute("add(add(1,?2),?100)"))?//?103.0
??}
}
class?AddFunction?extends?AbstractFunction{
??override?def?call(env:?java.util.Map[String,?Object],?arg1:?AviatorObject,?arg2:?AviatorObject):?AviatorObject?=?{
????val?left?=?FunctionUtils.getNumberValue(arg1,?env)
????val?right?=?FunctionUtils.getNumberValue(arg2,?env)
????new?AviatorDouble(left.doubleValue?+?right.doubleValue)
??}
??def?getName?=?"add"
}
注冊函數(shù)通過AviatorEvaluator.addFunction方法, 移除可以通過removeFunction。另外, FunctionUtils 提供了一些方便參數(shù)類型轉(zhuǎn)換的方法。
如果你的參數(shù)個數(shù)不確定,可以繼承 AbstractVariadicFunction 類,只要實現(xiàn)其中的 variadicCall 方法即可,比如我們實現(xiàn)一個找到第一個參數(shù)不為 null 的函數(shù):
object?test?{
??def?main(args:?Array[String]):?Unit?=?{
????AviatorEvaluator.addFunction(new?GetFirstNonNullFunction)
????System.out.println(AviatorEvaluator.execute("getFirstNonNull(1)"))?//?1
????System.out.println(AviatorEvaluator.execute("getFirstNonNull(1,2,3,4,nil,5)"))?//?1
????System.out.println(AviatorEvaluator.execute("getFirstNonNull(a,b,c,d)"))?//?null
??}
}
class?GetFirstNonNullFunction?extends?AbstractVariadicFunction?{
??override?def?variadicCall(env:?util.Map[String,?AnyRef],?args:?AviatorObject*):?AviatorObject?=?{
????if?(args?!=?null)?for?(arg?<-?args)?{
??????if?(arg.getValue(env)?!=?null)?return?arg
????}
????new?AviatorString(null)
??}
??override?def?getName?=?"getFirstNonNull"
}
當然,同時你仍然覆寫特定的 call 方法來自定義實現(xiàn)。
自定義函數(shù)在 4.0.0 之后也可以通過 lambda 來定義:
AviatorEvaluator.defineFunction("add",?"lambda?(x,y)?->?x?+?y?end")
AviatorEvaluator.exec("add(1,2)")????//3
函數(shù)加載器
從 4.0.0 開始,Aviator 還支持 FunctionLoader接口,可以用于自定義函數(shù)加載器:
class?function?extends?FunctionLoader{
??/**
????*?Invoked?when?function?not?found
????*
????*?@param?name?function?name
????*/
??override?def?onFunctionNotFound(name:?String):?AviatorFunction?=????
}
用戶可以自主實現(xiàn)函數(shù)加載器,當函數(shù)不能從當前求值器中找到的時候,將調(diào)用 loader 的onFunctionNotFound 方法進行查找。自定義的加載器,通過 AviatorEvaluator.addFunctionLoader(loader)注冊,可以注冊多個加載器,加載順序?qū)凑仗砑禹樞蜻M行查找,其中任何一個找到,都將中斷查找過程。
重載運算符
Aviator 支持的運算符參見操作符一節(jié)。部分用戶可能有重載這些內(nèi)置運算符的需求,例如在 Excel 里, & 不是位運算,而是字符串連接符,那么你可以通過 3.3.0 版本支持的運算符重載來實現(xiàn):
AviatorEvaluator.addOpFunction(OperatorType.BIT_AND,?new?AbstractFunction()?{
??????override?def?call(env:?util.Map[String,?Object],?arg1:?AviatorObject,?arg2:?AviatorObject)?=?new?AviatorString(arg1.getValue(env).toString?+?arg2.getValue(env).toString)
??????override?def?getName?=?"&"
????})
AviatorEvaluator.addOpFunction(opType, func) 就可以重載指定的運算符,重載后運行即可看到:
val?map?=?new?util.HashMap[String,Object]()
map.put("a","4")
val?result?=?AviatorEvaluator.execute("a&3",?map)
println(result)??????//43
val?map1?=?new?util.HashMap[String,Object]()
map1.put("a","hello")
val?result1?=??AviatorEvaluator.execute("a&'?world'",?map1)
println(result1)????//hello?world
請注意,運算符重載使用不當,一定程度上會帶來混亂,并且有一定的性能損失,請慎重使用。
編譯表達式
上面提到的例子都是直接執(zhí)行表達式, 事實上 Aviator 背后都幫你做了編譯并執(zhí)行的工作。你可以自己先編譯表達式, 返回一個編譯的結(jié)果, 然后傳入不同的env來復用編譯結(jié)果, 提高性能, 這是更推薦的使用方式:
val?expression?=?"a-(b-c)>100"
//?編譯表達式
val?compiledExp?=?AviatorEvaluator.compile(expression)
val?env?=?new?util.HashMap[String,Object]()
env.put("a",?100.3.asInstanceOf[Object])
env.put("b",?new?Integer(45))
env.put("c",?(-199.100).asInstanceOf[Object])
//?執(zhí)行表達式
val?result?=?compiledExp.execute(env).asInstanceOf[Boolean]
println(result)?//?false
通過compile方法可以將表達式編譯成Expression的中間對象, 當要執(zhí)行表達式的時候傳入env并調(diào)用Expression的execute方法即可。表達式中使用了括號來強制優(yōu)先級, 這個例子還使用了>用于比較數(shù)值大小, 比較運算符!=、==、>、>=、<、<=不僅可以用于數(shù)值, 也可以用于String、Pattern、Boolean等等, 甚至是任何用戶傳入的兩個都實現(xiàn)了java.lang.Comparable接口的對象之間。
編譯后的結(jié)果你可以自己緩存, 也可以交給 Aviator 幫你緩存, AviatorEvaluator內(nèi)部有一個全局的緩存池, 如果你決定緩存編譯結(jié)果, 可以通過:
public?static?Expression?compile(final?String?expression,?final?boolean?cached)
將cached設置為true即可, 那么下次編譯同一個表達式的時候?qū)⒅苯臃祷厣弦淮尉幾g的結(jié)果。
使緩存失效通過:
public?static?void?invalidateCache(String?expression)
訪問數(shù)組和集合
可以通過中括號去訪問數(shù)組和java.util.List對象, 可以通過map.key訪問java.util.Map中key對應的value, 一個例子:
val?list?=?new?util.ArrayList[String]
list.add("hello")
list.add("?world")
val?array?=?new?Array[Int](3)
array(0)?=?0
array(1)?=?1
array(2)?=?3
val?map?=?new?util.HashMap[String,Object]()
map.put("date",?new?Date())
val?env?=?new?util.HashMap[String,Object]()
env.put("list",?list)
env.put("array",?array)
env.put("mmap",?map)
println(AviatorEvaluator.execute("list[0]+list[1]",?env))?//?hello?world
println(AviatorEvaluator.execute("'array[0]+array[1]+array[2]='?+?(array[0]+array[1]+array[2])",?env))?//?array[0]+array[1]+array[2]=4
println(AviatorEvaluator.execute("'today?is?'?+?mmap.date?",?env))?//?today?is?Tue?Mar?19?11:42:51?CST?2019
如果函數(shù)調(diào)用或者括號表達式結(jié)果是一個數(shù)組或者List,你同樣可以可以通過 [index] 訪問:
println(AviatorEvaluator.exec("string.split(s,',')[0]",?"a,b,c,d"))????//a
三元操作符
Aviator 不提供if else語句, 但是提供了三元操作符?:用于條件判斷,使用上與 java 沒有什么不同:
println(AviatorEvaluator.exec("a>0??'yes':'no'",?new?Integer(1)))?//?yes
Aviator 的三元表達式對于兩個分支的結(jié)果類型并不要求一致,可以是任何類型,這一點與 java 不同。
正則表達式匹配
Aviator 支持類 Ruby 和 Perl 風格的表達式匹配運算,通過=~操作符, 如下面這個例子匹配 email 并提取用戶名返回:
val?email?=?"[email protected]"
val?env?=?new?util.HashMap[String,Object]()
env.put("email",?email)
val?username?=?AviatorEvaluator.execute("email=~/([\\w0-8]+)@\\w+[\\.\\w+]+/???$1?:?'unknow'?",?env).asInstanceOf[String]
println(username)?//?killme2008
email與正則表達式/([\w0-8]+@\w+[\.\w+]+)/通過=~操作符來匹配,結(jié)果為一個 Boolean 類 型, 因此可以用于三元表達式判斷,匹配成功的時候返回$1,指代正則表達式的分組 1,也就是用戶名,否則返回unknown。
Aviator 在表達式級別支持正則表達式,通過//括起來的字符序列構(gòu)成一個正則表達式,正則表達式可以用于匹配(作為=~的右操作數(shù))、比較大小。但是匹配僅能與字符串進行匹配。匹配成功后, Aviator 會自動將匹配成功的捕獲分組(capturing groups) 放入 env ${num}的變量中,其中$0 指代整個匹配的字符串,而$1表示第一個分組,$2表示第二個分組以此類推。
請注意,分組捕獲放入 env 是默認開啟的,因此如果傳入的 env 不是線程安全并且被并發(fā)使用,可能存在線程安全的隱患。關閉分組匹配,可以通過 AviatorEvaluator.setOption(Options.PUT_CAPTURING_GROUPS_INTO_ENV, false); 來關閉,對性能有稍許好處。
Aviator 的正則表達式規(guī)則跟 Java 完全一樣,因為內(nèi)部其實就是使用java.util.regex.Pattern做編譯的。
變量的語法糖
Aviator 有個方便用戶使用變量的語法糖, 當你要訪問變量a中的某個屬性b, 那么你可以通過a.b訪問到, 更進一步, a.b.c將訪問變量a的b屬性中的c屬性值, 推廣開來也就是說 Aviator 可以將變量聲明為嵌套訪問的形式。
TestAviator類符合JavaBean規(guī)范, 并且是 public 的,我們就可以使用語法糖:
object?test?{?
??def?main(args:?Array[String]):?Unit?=?{
????val?foo?=?new?Foo(100,?3.14f,?new?Date())
????val?env?=?new?util.HashMap[String,Object]()
????env.put("foo",?foo)
????println(AviatorEvaluator.execute("'foo.i?=?'+foo.i",?env))?//?foo.i?=?100
????println(AviatorEvaluator.execute("'foo.f?=?'+foo.f",?env))?//?foo.f?=?3.14
????println(AviatorEvaluator.execute("'foo.date.year?=?'+(foo.date.year+1900)",?env))?//?foo.date.year?=?2019
??}
}
class?Foo(var?i:?Int,?var?f:?Float,?var?date:?Date)?{
??def?getI:?Int?=?i
??def?setI(i:?Int):?Unit?=?{
????this.i?=?i
??}
??def?getF:?Float?=?f
??def?setF(f:?Float):?Unit?=?{
????this.f?=?f
??}
??def?getDate:?Date?=?date
??def?setDate(date:?Date):?Unit?=?{
????this.date?=?date
??}
}
nil 對象
nil是 Aviator 內(nèi)置的常量,類似 java 中的null,表示空的值。nil跟null不同的在于,在 java 中null只能使用在==、!=的比較運算符,而nil還可以使用>、>=、<、<=等比較運算符。Aviator 規(guī)定,任何對象都比nil大除了nil本身。用戶傳入的變量如果為null,將自動以nil替代。
AviatorEvaluator.execute("nil?==?nil");???//true
AviatorEvaluator.execute("?3>?nil");??????//true
AviatorEvaluator.execute("?true!=?nil");??//true
AviatorEvaluator.execute("?'?'>nil?");????//true
AviatorEvaluator.execute("?a==nil?");?????//true,?a?是?null
nil與String相加的時候,跟 java 一樣顯示為 null
日期比較
Aviator 并不支持日期類型,如果要比較日期,你需要將日期寫字符串的形式,并且要求是形如 “yyyy-MM-dd HH:mm:ss:SS”的字符串,否則都將報錯。字符串跟java.util.Date比較的時候?qū)⒆詣愚D(zhuǎn)換為Date對象進行比較:
val?env?=?new?util.HashMap[String,Object]()
val?date?=?new?Date()
val?dateStr?=?new?SimpleDateFormat("yyyy-MM-dd?HH:mm:ss:SS").format(date)
env.put("date",?date)
env.put("dateStr",?dateStr)
var?result?=?AviatorEvaluator.execute("date==dateStr",?env).asInstanceOf[Boolean]
println(result)?//?true
result?=?AviatorEvaluator.execute("date?>?'2010-12-20?00:00:00:00'?",?env).asInstanceOf[Boolean]
println(result)//?true
result?=?AviatorEvaluator.execute("date?'2200-12-20?00:00:00:00'?",?env).asInstanceOf[Boolean]
println(result)//?true
result?=?AviatorEvaluator.execute("date==date?",?env).asInstanceOf[Boolean]
println(result)//?true
也就是說String除了能跟String比較之外,還能跟nil和java.util.Date對象比較。
大數(shù)計算和精度
從 2.3.0 版本開始,aviator 開始支持大數(shù)字計算和特定精度的計算, 本質(zhì)上就是支持java.math.BigInteger和java.math.BigDecimal兩種類型, 這兩種類型在 aviator 中簡稱為big int和decimal類型。類似99999999999999999999999999999999這樣的數(shù)字在 Java 語言里是沒辦法編譯通過 的, 因為它超過了Long類型的范圍, 只能用BigInteger來封裝。但是 aviator 通過包裝,可以直接支持這種大整數(shù)的計算,例如:
println(AviatorEvaluator.execute("99999999999999999999999999999999?+?99999999999999999999999999999999"))
//結(jié)果:199999999999999999999999999999998
字面量表示
big int和decimal的表示與其他數(shù)字不同,兩條規(guī)則:
以大寫字母N為后綴的整數(shù)都被認為是big int,如1N,2N,9999999999999999999999N等, 都是big int類型。
超過long范圍的整數(shù)字面量都將自動轉(zhuǎn)換為big int類型。
以大寫字母M為后綴的數(shù)字都被認為是decimal, 如1M,2.222M, 100000.9999M等, 都是decimal類型。
用戶也可以通過變量傳入這兩種類型來參與計算。
如果用戶覺的給浮點數(shù)添加 M 后綴比較繁瑣,也可以強制所有浮點數(shù)解析為 BigDecimal,通過代碼開啟下列選項即可:
AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL,?true)
運算
big int和decimal的運算,跟其他數(shù)字類型long,double沒有什么區(qū)別,操作符仍然是一樣的。aviator重載了基本算術操作符來支持這兩種新類型:
var?rt?=?AviatorEvaluator.exec("9223372036854775807100.356M?*?2")
println(rt?+?"?"?+?rt.getClass)?//?18446744073709551614200.712?class?java.math.BigDecimal
rt?=?AviatorEvaluator.exec("92233720368547758074+1000")
println(rt?+?"?"?+?rt.getClass)?//?92233720368547759074?class?java.math.BigInteger
val?a?=?new?BigInteger(String.valueOf(Long.MaxValue)?+?String.valueOf(Long.MaxValue))
val?b?=?new?java.math.BigDecimal("3.2")
val?c?=?new?java.math.BigDecimal("9999.99999")
rt?=?AviatorEvaluator.exec("a+10000000000000000000",?a)
println(rt?+?"?"?+?rt.getClass)?//?92233720368547758089223372036854775807?class?java.math.BigInteger
rt?=?AviatorEvaluator.exec("b+c*2",?b,?c)
println(rt?+?"?"?+?rt.getClass)?//?20003.19998?class?java.math.BigDecimal
rt?=?AviatorEvaluator.exec("a*b/c",?a,?b,?c)
println(rt?+?"?"?+?rt.getClass)?//?2.951479054745007313280155218459508E+34?class?java.math.BigDecimal
類型轉(zhuǎn)換和提升
當big int或者decimal和其他類型的數(shù)字做運算的時候,按照long < big int < decimal < double的規(guī)則做提升, 也就是說運算的數(shù)字如果類型不一致, 結(jié)果的類型為兩者之間更“高”的類型。例如:
1 + 3N, 結(jié)果為big int的4N
1 + 3.1M,結(jié)果為decimal的4.1M
1N + 3.1M,結(jié)果為decimal的 4.1M
1.0 + 3N,結(jié)果為double的4.0
1.0 + 3.1M,結(jié)果為double的4.1
decimal 的計算精度
Java 的java.math.BigDecimal通過java.math.MathContext支持特定精度的計算,任何涉及到金額的計算都應該使用decimal類型。
默認 Aviator 的計算精度為MathContext.DECIMAL128,你可以自定義精度, 通過:
AviatorEvaluator.setOption(Options.MATH_CONTEXT,?MathContext.DECIMAL64)
即可設置,更多關于decimal的精度問題請看java.math.BigDecimal的 javadoc 文檔。
強大的 seq 庫
aviator 擁有強大的操作集合和數(shù)組的 seq 庫。整個庫風格類似函數(shù)式編程中的高階函數(shù)。在 aviator 中, 數(shù)組以及java.util.Collection下的子類都稱為seq,可以直接利用 seq 庫進行遍歷、過濾和聚合等操作。
例如,假設我有個 list:
val?env?=?new?util.HashMap[String,Object]()
val?list?=?new?util.ArrayList[Integer]
list.add(3)
list.add(20)
list.add(10)
env.put("list",?list)
var?result?=?AviatorEvaluator.execute("count(list)",?env)
println(result)?//?3
result?=?AviatorEvaluator.execute("reduce(list,+,0)",?env)
println(result)?//?33
result?=?AviatorEvaluator.execute("filter(list,seq.gt(9))",?env)
println(result)?//?[20,?10]
result?=?AviatorEvaluator.execute("include(list,10)",?env)
println(result)?//?true
result?=?AviatorEvaluator.execute("sort(list)",?env)
println(result)?//?[3,?10,?20]
AviatorEvaluator.execute("map(list,println)",?env)
我們可以:
求長度: count(list)
求和: reduce(list,+,0), reduce函數(shù)接收三個參數(shù),第一個是seq,第二個是聚合的函數(shù),如+等,第三個是聚合的初始值
過濾: filter(list,seq.gt(9)), 過濾出list中所有大于9的元素并返回集合; seq.gt函數(shù)用于生成一個謂詞,表示大于某個值
判斷元素在不在集合里: include(list,10)
排序: sort(list)
遍歷整個集合: map(list,println), map接受的第二個函數(shù)將作用于集合中的每個元素,這里簡單地調(diào)用println打印每個元素
其他還有:
seq.some(list, pred) 當集合中只要有一個元素滿足謂詞函數(shù) pred 返回 true,立即返回 true,否則為 false。
seq.every(list, pred) 當集合里的每個元素都滿足謂詞函數(shù) pred 返回 true,則結(jié)果為 true,否則返回 false。
seq.not_any(list, pred),當集合里的每個元素都滿足謂詞函數(shù) pred 返回 false,則結(jié)果為 true,否則返回 false。
以及 seq.or(p1, p2, …) 和 seq.and(p1, p2, …) 用于組合 seq.gt、seq.lt 等謂詞函數(shù)。
兩種運行模式
默認 AviatorEvaluator 以執(zhí)行速度優(yōu)先:
AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL,?AviatorEvaluator.EVAL)
你可以修改為編譯速度優(yōu)先,這樣不會做編譯優(yōu)化:
AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL,?AviatorEvaluator.COMPILE)
調(diào)試信息
如果想查看每個表達式生成的字節(jié)碼,可以通過打開 Trace 選項:
AviatorEvaluator.setOption(Options.TRACE,?true)
默認是打印到標準輸出,你可以改變輸出指向:
AviatorEvaluator.setTraceOutputStream(new?FileOutputStream(new?File("aviator.log")))
5.語法手冊
下面是 Aviator 詳細的語法規(guī)則定義。
數(shù)據(jù)類型
Number類型: 數(shù)字類型,支持四種類型,分別是long,double,java.math.BigInteger(簡稱 big int)和java.math.BigDecimal(簡 稱 decimal),規(guī)則如下:
任何以大寫字母 N 結(jié)尾的整數(shù)都被認為是 big int
任何以大寫字母 M 結(jié)尾的數(shù)字都被認為是 decimal
其他的任何整數(shù)都將被轉(zhuǎn)換為 Long
其他任何浮點數(shù)都將被轉(zhuǎn)換為 Double
超過 long 范圍的整數(shù)字面量都將自動轉(zhuǎn)換為 big int 類型、
其中 big int 和 decimal 是 2.3.0 版本開始引入的。數(shù)字還支持十六進制(以0x或者0X開頭的數(shù)字), 以及科學計數(shù)法,如1e-3等。不支持其他進制。
String類型: 字符串類型,單引號或者雙引號括起來的文本串,如’hello world’, 變量如果傳入的是String或者Character也將轉(zhuǎn)為String類型
Bool類型: 常量true和false,表示真值和假值,與 java 的Boolean.TRUE和Boolean.False對應
Pattern類型: 正則表達式, 以//括起來的字符串,如/\d+/,內(nèi)部 實現(xiàn)為java.util.Pattern
變量類型: 與 Java 的變量命名規(guī)則相同,變量的值由用戶傳入
nil類型: 常量nil,類似 java 中的null,但是nil比較特殊,nil不僅可以參與==、!=的比較, 也可以參與>、>=、<、<=的比較,Aviator 規(guī)定任何類型都大于nil除了nil本身,nil==nil返回true。用戶傳入的變量值如果為null,那么也將作為nil處理,nil打印為null
操作符
算術運算符
Aviator 支持常見的算術運算符,包括+ - * / %五個二元運算符,和一元運算符-(負)。其中- * / %和一元的-僅能作用于Number類型。
+不僅能用于Number類型,還可以用于String的相加,或者字符串與其他對象的相加。
Aviator 規(guī)定,任何類型與String相加,結(jié)果為String。
邏輯運算符
Avaitor 的支持的邏輯運算符包括,一元否定運算符!,以及邏輯與的&&,邏輯或的||。邏輯運算符的操作數(shù)只能為Boolean。
&&和||都執(zhí)行短路規(guī)則。
關系運算符
Aviator 支持的關系運算符包括<, <=, >, >=以及==和!= 。
關系運算符可以作用于Number之間、String之間、Pattern之間、Boolean之間、變量之間以及其他類型與nil之間的關系比較, 不同類型除了nil之外不能相互比較。
位運算符
Aviator 支持所有的 Java 位運算符,包括&, |, ^, ~, >>, <<, >>>。
匹配運算符
匹配運算符=~用于String和Pattern的匹配,它的左操作數(shù)必須為String,右操作數(shù)必須為Pattern。匹配成功后,Pattern的分組將存于變量$num,num為分組索引。
三元運算符
Aviator 沒有提供if else語句,但是提供了三元運算符?:,形式為bool ? exp1: exp2。其中bool必須為Boolean類型的表達式, 而exp1和exp2可以為任何合法的 Aviator 表達式,并且不要求exp1和exp2返回的結(jié)果類型一致。
6.內(nèi)置函數(shù)
完整的內(nèi)置函數(shù)列表參見內(nèi)置函數(shù)。
https://github.com/killme2008/aviatorscript/wiki/%E5%86%85%E7%BD%AE%E5%87%BD%E6%95%B0
7.選項列表
AviatorEvaluator.setOption(opt, val) 支持定義求值器的行為,完整的 Options 枚舉選項參見完整選項說明
https://github.com/killme2008/aviatorscript/wiki/%E5%AE%8C%E6%95%B4%E9%80%89%E9%A1%B9%E5%88%97%E8%A1%A8%E8%AF%B4%E6%98%8E
8.JavaDoc
http://fnil.net/aviator/apidocs/
9.4.0功能詳解
https://github.com/killme2008/aviatorscript/wiki/
10.參考鏈接
主頁:http://fnil.net/aviator/
示例:
https://github.com/killme2008/aviatorscript/tree/master/src/test/java/com/googlecode/aviator/example
官方指南:
https://github.com/killme2008/aviatorscript/wiki
? 作者?|??墨小柒
來源 |??csdn.net/sinat_37690778/article/details/88668639