pom

<dependency> <groupId>com.googlecode.aviator</groupId> <artifactId>aviator</artifactId> <version>4.2.10</version> </dependency> <dependency> <groupId>org.mvel</groupId> <artifactId>mvel2</artifactId> <version>2.4.10.Final</version> </dependency>
對單一map的簡單操作

import java.util.HashMap; import java.util.Map; import com.googlecode.aviator.AviatorEvaluator; import com.googlecode.aviator.runtime.function.AbstractFunction; import com.googlecode.aviator.runtime.function.FunctionUtils; import com.googlecode.aviator.runtime.type.AviatorBigInt; import com.googlecode.aviator.runtime.type.AviatorObject; public class App { static{ //注冊函數 AviatorEvaluator.addFunction(new MinFunction()); } public static void main( String[] args ) { Map<String, Object> sourceMapItem = new HashMap<String, Object>(); sourceMapItem.put("pt", "mi"); sourceMapItem.put("ab", "abc"); sourceMapItem.put("xy", "xyz"); sourceMapItem.put("int1", 135); sourceMapItem.put("int2", 68); sourceMapItem.put("decimal2", 19.83); sourceMapItem.put("mydate", "2020-10-10 28:35:00"); sourceMapItem.put("value", 999); String expStr = "pt == 'mi'"; Object result; result = AviatorEvaluator.execute(expStr, sourceMapItem); System.out.println(expStr+" --- "+result); //邏輯與 + 簡單表達式 expStr = "pt == 'mi' && ab == 'abc' && int1 > 100 && decimal2 < 20.50"; result = AviatorEvaluator.execute(expStr, sourceMapItem); System.out.println(expStr+" --- "+result); //邏輯與或組合 expStr = "pt == 'mi1' || (decimal2 < 20.50 && xy+'X' == 'xyzX')"; result = AviatorEvaluator.execute(expStr, sourceMapItem); System.out.println(expStr+" --- "+result); //三目運算 expStr = "pt == 'mi1' ? ab == 'ab' : ab == 'abc'"; result = AviatorEvaluator.execute(expStr, sourceMapItem); System.out.println(expStr+" --- "+result); //函數 expStr = "pt != 'mi1' && string.length(xy) >= 5 "; result = AviatorEvaluator.execute(expStr, sourceMapItem); System.out.println(expStr+" --- "+result); //自定義函數 expStr = "pt == 'mi1' || myMin(int2 , int1) > 10 "; result = AviatorEvaluator.execute(expStr, sourceMapItem); System.out.println(expStr+" --- "+result); } static class MinFunction extends AbstractFunction { @Override public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) { Number left = FunctionUtils.getNumberValue(arg1, env); Number right = FunctionUtils.getNumberValue(arg2, env); return new AviatorBigInt(Math.min(left.doubleValue(), right.doubleValue())); } public String getName() { return "myMin"; } } }
輸出結果
pt == 'mi' --- true
pt == 'mi' && ab == 'abc' && int1 > 100 && decimal2 < 20.50 --- true pt == 'mi1' || (decimal2 < 20.50 && xy+'X' == 'xyzX') --- true pt == 'mi1' ? ab == 'ab' : ab == 'abc' --- true pt != 'mi1' && string.length(xy) >= 5 --- false pt == 'mi1' || myMin(int2 , int1) > 10 --- true
一個擴展的任務,Aviator對嵌套map進行stream過濾
import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import com.googlecode.aviator.AviatorEvaluator; public class MapForFilter { final static String EXPSTR = "(pt == 'mi' && ab == 'abc' && int1 > 100) || " + "(decimal2 < 20.50 && string.length(xy) >= 5)"; public static void main( String[] args ) { aviatorEvaluatorDemo(); } private static void aviatorEvaluatorDemo() { Map<String, Map<String, Object>> sourceMap = fillData(); Map<String, Map<String, Object>> resultdMap = parseMapForFilter(sourceMap,EXPSTR); System.out.println("過濾后:"+resultdMap); } private static Map<String, Map<String, Object>> fillData() { Map<String, Map<String, Object>> sourceMap = new HashMap<String, Map<String, Object>>(); Map<String, Object> sourceMapItem1 = new HashMap<String, Object>(); sourceMapItem1.put("pt", "mi"); sourceMapItem1.put("ab", "abc"); sourceMapItem1.put("xy", "xyz"); sourceMapItem1.put("int1", 135); sourceMapItem1.put("int2", 68); sourceMapItem1.put("decimal2", 19.83); sourceMapItem1.put("mydate", "2020-10-10 28:35:00"); sourceMapItem1.put("value", 999); Map<String, Object> sourceMapItem2 = new HashMap<String, Object>(); sourceMapItem2.put("pt", "oppo"); sourceMapItem2.put("ab", "ab"); sourceMapItem2.put("xy", "xy"); sourceMapItem2.put("int1", 24); sourceMapItem2.put("int2", 56); sourceMapItem2.put("decimal2", 519.83); sourceMapItem2.put("mydate", "2020-10-11 28:35:00"); sourceMapItem2.put("value", 888); Map<String, Object> sourceMapItem3 = new HashMap<String, Object>(); sourceMapItem3.put("pt", "oppo"); sourceMapItem3.put("ab", "cde"); sourceMapItem3.put("xy", "xy"); sourceMapItem3.put("int1", 213); sourceMapItem3.put("int2", 473); sourceMapItem3.put("decimal2", 119.83); sourceMapItem3.put("mydate", "2020-10-12 28:35:00"); sourceMapItem3.put("value", 777); Map<String, Object> sourceMapItem4 = new HashMap<String, Object>(); sourceMapItem4.put("pt", "oppo"); sourceMapItem4.put("ab", "fgh"); sourceMapItem4.put("xy", "xyz123"); sourceMapItem4.put("int1", 156); sourceMapItem4.put("int2", 215); sourceMapItem4.put("decimal2", 15.92); sourceMapItem4.put("mydate", "2020-10-13 28:35:00"); sourceMapItem4.put("value", 666); sourceMap.put("2020-10-10",sourceMapItem1); sourceMap.put("2020-10-11",sourceMapItem2); sourceMap.put("2020-10-12",sourceMapItem3); sourceMap.put("2020-10-13",sourceMapItem4); return sourceMap; } public static Map<String, Map<String, Object>> parseMapForFilter(Map<String, Map<String, Object>> sourceMap,String exp) { return Optional.ofNullable(sourceMap).map( (v) -> { Map<String, Map<String, Object>> params = v.entrySet().stream() .filter(map -> checkItem(map.getValue(),exp)) .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); return params; } ).orElse(null); } private static boolean checkItem(Map<String, Object> itemMap,String exp) { Object result = AviatorEvaluator.execute(exp, itemMap); return (boolean) result; } }
MVEL的實現同樣的過濾任務
為了適應MVEL,注意表達式的字符有少許不同。
import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import org.mvel2.MVEL; public class MapForFilterMvel { final static String EXPSTR = "(m.pt == 'mi' && m.ab == 'abc' && m.int1 > 100) || " + "(m.decimal2 < 20.50 && m.xy.length()>5)"; public static void main( String[] args ) { mvelDemo(); } private static void mvelDemo() { Map<String, Map<String, Object>> sourceMap = fillData(); Map<String, Map<String, Object>> resultdMap = parseMapForMvelFilter(sourceMap); System.out.println("過濾后:"+resultdMap); } private static Map<String, Map<String, Object>> parseMapForMvelFilter(Map<String, Map<String, Object>> sourceMap) { return Optional.ofNullable(sourceMap).map( (v) -> { Map<String, Map<String, Object>> params = v.entrySet().stream() .filter(map -> checkItemByMvel(map.getValue())) .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); return params; } ).orElse(null); } private static boolean checkItemByMvel(Map<String, Object> value) { Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("m", value); Object object = MVEL.eval(EXPSTR, paramMap); return (boolean)object; } private static Map<String, Map<String, Object>> fillData() { Map<String, Map<String, Object>> sourceMap = new HashMap<String, Map<String, Object>>(); Map<String, Object> sourceMapItem1 = new HashMap<String, Object>(); sourceMapItem1.put("pt", "mi"); sourceMapItem1.put("ab", "abc"); sourceMapItem1.put("xy", "xyz"); sourceMapItem1.put("int1", 135); sourceMapItem1.put("int2", 68); sourceMapItem1.put("decimal2", 19.83); sourceMapItem1.put("mydate", "2020-10-10 28:35:00"); sourceMapItem1.put("value", 999); Map<String, Object> sourceMapItem2 = new HashMap<String, Object>(); sourceMapItem2.put("pt", "oppo"); sourceMapItem2.put("ab", "ab"); sourceMapItem2.put("xy", "xy"); sourceMapItem2.put("int1", 24); sourceMapItem2.put("int2", 56); sourceMapItem2.put("decimal2", 519.83); sourceMapItem2.put("mydate", "2020-10-11 28:35:00"); sourceMapItem2.put("value", 888); Map<String, Object> sourceMapItem3 = new HashMap<String, Object>(); sourceMapItem3.put("pt", "oppo"); sourceMapItem3.put("ab", "cde"); sourceMapItem3.put("xy", "xy"); sourceMapItem3.put("int1", 213); sourceMapItem3.put("int2", 473); sourceMapItem3.put("decimal2", 119.83); sourceMapItem3.put("mydate", "2020-10-12 28:35:00"); sourceMapItem3.put("value", 777); Map<String, Object> sourceMapItem4 = new HashMap<String, Object>(); sourceMapItem4.put("pt", "oppo"); sourceMapItem4.put("ab", "fgh"); sourceMapItem4.put("xy", "xyz123"); sourceMapItem4.put("int1", 156); sourceMapItem4.put("int2", 215); sourceMapItem4.put("decimal2", 15.92); sourceMapItem4.put("mydate", "2020-10-13 28:35:00"); sourceMapItem4.put("value", 666); sourceMap.put("2020-10-10",sourceMapItem1); sourceMap.put("2020-10-11",sourceMapItem2); sourceMap.put("2020-10-12",sourceMapItem3); sourceMap.put("2020-10-13",sourceMapItem4); return sourceMap; } }
對map集合的過濾:結果:
過濾后:
{
2020-10-10={ab=abc, xy=xyz, int2=68, mydate=2020-10-10 28:35:00, int1=135, pt=mi, decimal2=19.83, value=999},
2020-10-13={ab=fgh, xy=xyz123, int2=215, mydate=2020-10-13 28:35:00, int1=156, pt=oppo, decimal2=15.92, value=666}
}
Aviator的優缺點
final static String EXPSTR = "(pt == 'mi' && ab == 'abc' && int1 > 100) || (decimal2 < 20.50 && string.length(xy) >= 5)";
- 更輕量級。
- 對map的支持非常好,可以說就是為了Map量身定做的,對key變量直接使用就可以了。
- 函數只能使用內置函數或者自定義函數。
- 不支持對象的屬性和方法。
- 不支持if else和for循環。
MVEL的優點
final static String EXPSTR = "(m.pt == 'mi' && m.ab == 'abc' && m.int1 > 100) || (m.decimal2 < 20.50 && m.xy.length()>5)";
- 功能更加強大。
- 使用map需要再包一層,用於指示map的根。稍微有些限制,但也不影響使用,固定一個map變量名就好了。
- 支持對象屬性、方法,這就厲害了,可以復用全部的java內置class,也可以使用你自己寫的class的屬性和方法。也可以自定義方法。
- 支持對象new操作,支持斷言,支持對象賦值。
- 支持if else流程,支持循環。
操作符列表
序號 | 操作符 | 結合性 | 操作數限制 |
---|---|---|---|
0 | () [ ] | 從左到右 | ()用於函數調用,[ ]用於數組和java.util.List的元素訪問,要求[indx]中的index必須為整型 |
1 | ! - ~ | 從右到左 | ! 能用於Boolean,- 僅能用於Number,~僅能用於整數 |
2 | * / % | 從左到右 | Number之間 |
3 | + - | 從左到右 | + - 都能用於Number之間, + 還能用於String之間,或者String和其他對象 |
4 | << >> >>> | 從左到右 | 僅能用於整數 |
5 | < <= > >= | 從左到右 | Number之間、String之間、Pattern之間、變量之間、其他類型與nil之間 |
6 | == != =~ | 從左到右 | ==和!=作用於Number之間、String之間、Pattern之間、變量之間、其他類型與nil之間以及String和java.util.Date之間,=~僅能作用於String和Pattern之間 |
7 | & | 從左到右 | 整數之間 |
8 | ^ | 從左到右 | 整數之間 |
9 | ¦ | 從左到右 | 整數之間 |
10 | && | 從左到右 | Boolean之間,短路 |
11 | ¦¦ | 從左到右 | Boolean之間,短路 |
12 | ? : | 從右到左 | 第一個操作數的結果必須為Boolean,第二和第三操作數結果無限制 |
內置函數
函數名稱 | 說明 |
---|---|
sysdate() | 返回當前日期對象java.util.Date |
rand() | 返回一個介於0-1的隨機數,double類型 |
print([out],obj) | 打印對象,如果指定out,向out打印,否則輸出到控制台 |
println([out],obj) | 與print類似,但是在輸出后換行 |
now() | 返回System.currentTimeMillis |
long(v) | 將值的類型轉為long |
double(v) | 將值的類型轉為double |
str(v) | 將值的類型轉為string |
date_to_string(date,format) | 將Date對象轉化化特定格式的字符串,2.1.1新增 |
string_to_date(source,format) | 將特定格式的字符串轉化為Date對象,2.1.1新增 |
string.contains(s1,s2) | 判斷s1是否包含s2,返回Boolean |
string.length(s) | 求字符串長度,返回Long |
string.startsWith(s1,s2) | s1是否以s2開始,返回Boolean |
string.endsWith(s1,s2) | s1是否以s2結尾,返回Boolean |
string.substring(s,begin[,end]) | 截取字符串s,從begin到end,end如果忽略的話,將從begin到結尾,與java.util.String.substring一樣。 |
string.indexOf(s1,s2) | java中的s1.indexOf(s2),求s2在s1中的起始索引位置,如果不存在為-1 |
string.split(target,regex,[limit]) | Java里的String.split方法一致,2.1.1新增函數 |
string.join(seq,seperator) | 將集合seq里的元素以seperator為間隔連接起來形成字符串,2.1.1新增函數 |
string.replace_first(s,regex,replacement) | Java里的String.replaceFirst 方法,2.1.1新增 |
string.replace_all(s,regex,replacement) | Java里的String.replaceAll方法 ,2.1.1新增 |
math.abs(d) | 求d的絕對值 |
math.sqrt(d) | 求d的平方根 |
math.pow(d1,d2) | 求d1的d2次方 |
math.log(d) | 求d的自然對數 |
math.log10(d) | 求d以10為底的對數 |
math.sin(d) | 正弦函數 |
math.cos(d) | 余弦函數 |
math.tan(d) | 正切函數 |
map(seq,fun) | 將函數fun作用到集合seq每個元素上,返回新元素組成的集合 |
filter(seq,predicate) | 將謂詞predicate作用在集合的每個元素上,返回謂詞為true的元素組成的集合 |
count(seq) | 返回集合大小 |
include(seq,element) | 判斷element是否在集合seq中,返回boolean值 |
sort(seq) | 排序集合,僅對數組和List有效,返回排序后的新集合 |
reduce(seq,fun,init) | fun接收兩個參數,第一個是集合元素,第二個是累積的函數,本函數用於將fun作用在集合每個元素和初始值上面,返回最終的init值 |
seq.eq(value) | 返回一個謂詞,用來判斷傳入的參數是否跟value相等,用於filter函數,如filter(seq,seq.eq(3)) 過濾返回等於3的元素組成的集合 |
seq.neq(value) | 與seq.eq類似,返回判斷不等於的謂詞 |
seq.gt(value) | 返回判斷大於value的謂詞 |
seq.ge(value) | 返回判斷大於等於value的謂詞 |
seq.lt(value) | 返回判斷小於value的謂詞 |
seq.le(value) | 返回判斷小於等於value的謂詞 |
seq.nil() | 返回判斷是否為nil的謂詞 |
seq.exists() | 返回判斷不為nil的謂詞 |
常量和變量
值 | 說明 |
---|---|
true | 真值 |
false | 假值 |
nil | 空值 |
$digit |
正則表達式匹配成功后的分組,$0 表示匹配的字符串,$1 表示第一個分組 etc. |
參考資料
5.0版以后成為了aviatorscript
https://github.com/killme2008/aviatorscript