欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java 中運(yùn)行字符串表達(dá)式的方法

 更新時(shí)間:2018年11月22日 10:50:09   投稿:mrr  
這篇文章主要介紹了Java 中運(yùn)行字符串表達(dá)式的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

在日常的開發(fā)中,偶爾會(huì)遇到運(yùn)行字符串表達(dá)式的情況,通常這樣的需求會(huì)對(duì)需求進(jìn)行進(jìn)一步分析,然后進(jìn)行進(jìn)一步 “特殊化”,最后直接寫到硬代碼中,這樣做的話,就不太好擴(kuò)展了;也有另外的處理方式是采用 Java 內(nèi)置的 JavaScript 引擎等運(yùn)行字符串表達(dá)式,但是內(nèi)置引擎也有弊端,比如頻繁運(yùn)行片段式的字符串的效率非常低,并且與 Java 之間的數(shù)據(jù)交互比較麻煩,于是,便產(chǎn)生了寫一個(gè)“字符串表達(dá)式計(jì)算引擎”的想法...

寫的過(guò)程其實(shí)沒想象中那么麻煩,最初版大概在今年 5 月底寫好,但是結(jié)構(gòu)比較混亂,寫的時(shí)候基本上是一邊寫一邊修,最后 if...else...這樣的條件以及嵌套太多,以至于自己也無(wú)法完全理解,好在邏輯基本完善,運(yùn)行也沒出現(xiàn)意料之外的情況(也許出現(xiàn)了,只是沒發(fā)現(xiàn)),并且是自己用,所以就沒太在意。

前兩個(gè)星期,又抽空重新整理了一遍,重新梳理了一下結(jié)構(gòu),擴(kuò)展了一些功能,重新定義了一下各種符號(hào)的 “語(yǔ)義邊界”,盡可能保證運(yùn)算符與 Java 本身運(yùn)算符一致,邏輯結(jié)構(gòu)也更清晰,不會(huì)產(chǎn)生意外情況等。

RunnerUtil 在語(yǔ)法上很大程度參考了 JavaScript 的語(yǔ)法,比如用花括號(hào)表示一個(gè)鍵值對(duì)“對(duì)象”(實(shí)際上會(huì)被解析成 HashMap),鍵名不必用單引號(hào)或雙引號(hào)包裹,單引號(hào)雙引號(hào)均表示普通字符串,通過(guò)點(diǎn)號(hào)(.)和方括號(hào)鏈?zhǔn)饺≈档?。這對(duì)于從事 JavaWeb 開發(fā)的同學(xué)來(lái)說(shuō),書寫起來(lái)也比較方便?,F(xiàn)在已經(jīng)實(shí)現(xiàn)了絕大部分功能,已實(shí)現(xiàn)的功能也經(jīng)過(guò)一定測(cè)試,確保能“符合期望”的運(yùn)行,如果有想法和建議也希望多多的提一下哈。

項(xiàng)目地址: github.com/xua74453185…

基本用法介紹

字符串表達(dá)式通過(guò)一個(gè)叫 RunnerUtil 的靜態(tài)類運(yùn)行,可以直接運(yùn)行得到表達(dá)式結(jié)果,也可以解析一個(gè)表達(dá)式后在需要的時(shí)候運(yùn)行,RunnerUtil 主要有以下幾個(gè)方法:

RunnerUtil.run(/* expression */); 直接運(yùn)行表達(dá)式并得到結(jié)果;
RunnerUtil.run("1 + 1"); // 2
RunnerUtil.run(" 'Hello' + ' ' + 'World!' "); // "Hello World!"
RunnerUtil.run(/* expression */, / * data */); 運(yùn)行含有變量的表達(dá)式,后面的 data 是變量將要指向的“值”;
RunnerUtil.parseRun(/* expression */); 直接運(yùn)行“另一種”表達(dá)式,并得到結(jié)果,如:
RunnerUtil.parseRun("Hello {{  'World!'  }}"); // "Hello World!"

可見 #parseRun 是運(yùn)行包含“插值語(yǔ)法”的表達(dá)式,被包裹的內(nèi)容被作為一個(gè)表達(dá)式單獨(dú)運(yùn)行;

字符串中可以包含多個(gè)插值語(yǔ)法表達(dá)式,但不能嵌套和交叉,也可以運(yùn)行含有變量的表達(dá)式。

Runner runner = RunnerUtil.parse(/* expression */);

解析一個(gè)字符串表達(dá)式,得到一個(gè)“字符串表達(dá)式運(yùn)行器” —— Runner,然后調(diào)用其 run(/ * data */) 方法運(yùn)行并得到結(jié)果。

語(yǔ)法及運(yùn)算詳細(xì)介紹

作為一個(gè)具有一定“語(yǔ)言特點(diǎn)”的東西,它定義了一些自己的語(yǔ)法、數(shù)據(jù)類型、運(yùn)算類型等,但大部分都與 Java 和 JavaScript 兼容,相同符號(hào)具有相同或相似的語(yǔ)言意義。

數(shù)據(jù)類型:

1、null:這是一個(gè)關(guān)鍵字,但因?yàn)樗虾妥兞康亩x規(guī)則,所以需要注意一下,同樣被定義為關(guān)鍵字的還有 true 和 false。

2、boolean:true 和 false

RunnerUtil.run(" null  "); // null
RunnerUtil.run("  true "); // true
RunnerUtil.run("false"); // false
// 表達(dá)式中多余的空格自動(dòng)忽略

數(shù)字:這里面的數(shù)字統(tǒng)一采用 Java 里的 int 和 double 型數(shù)據(jù),直接參與運(yùn)算的也只有是這兩種類型,區(qū)別就是有沒有小數(shù)點(diǎn)。

RunnerUtil.run(" 12 "); // 12
RunnerUtil.run(" 12.5 "); // 12.5
// 表示數(shù)字必須是連續(xù),中間不能有空格的
// 否則將拋出異常,如
RunnerUtil.run(" 12. 5"); // 異常
RunnerUtil.run(" 1 2 "); // 異常

表示數(shù)字的字符之間應(yīng)該是連續(xù)的,如:25、36.9 等;如果是不連續(xù)的會(huì)拋出異常,如:2 5、36 .9 等;

字符串:Java 里的字符串用雙引號(hào)包裹,在這里還將表示字符的單引號(hào)“征用”,雙引號(hào)單引號(hào)包裹的都表示普通字符串的直接值,這樣做也是為了書寫方便(與 JavaScript 相似),同時(shí)也就沒有了 char 類型數(shù)據(jù)啦啦啦……

RunnerUtil.run(" 'abcdef' "); // "abcdef"
RunnerUtil.run(" \"abcdef\" "); // "abcdef"
RunnerUtil.run(" 'abc  def' "); // "abc  def"

List:實(shí)際上是 ArrayList,對(duì)應(yīng) JavaScript 里面的數(shù)組。Java 的數(shù)組也對(duì)應(yīng) JavaScript 數(shù)組。

RunnerUtil.run(" { } "); 
// 總是返回一個(gè)空ArrayList
RunnerUtil.run(" {1,2,,4, } "); 
// 總是返回一個(gè)包含:1、2、null、4 這幾項(xiàng)的 ArrayList
// 可以看出最后一個(gè)逗號(hào)之后如果是結(jié)束符號(hào)會(huì)自動(dòng)忽略
// 中間的逗號(hào)與逗號(hào)之間若沒有其他非空白符號(hào)會(huì)插入一個(gè) null 值

Map:實(shí)際上是 HashMap,對(duì)應(yīng) JavaScript 里的對(duì)象。同樣對(duì)應(yīng) JavaScript 對(duì)象的還有普通 POJO。
Map 對(duì)應(yīng)的是 JavaScript 里的對(duì)象,但是在這里 Map 的鍵可以是這些數(shù)據(jù)類型:

null、true / false、數(shù)字(int / double)、字符串,不能再是其他 Java 對(duì)象了

RunnerUtil.run(" {:} "); // 總是返回一個(gè)空 HashMap,
// 注意與空 List 的異同,都是用花括號(hào)表示
// 但空 Map 里面需要有一個(gè)冒號(hào),否則就是 List

RunnerUtil.run(" {key: 'value'}");
// 總是返回包含一個(gè)鍵值對(duì)的 HashMap
// 可以看出,對(duì)象的鍵名是字符串的話可以不用引號(hào)包裹
// 但是值必須被包裹
RunnerUtil.run(" {true: 'value'}"); // 鍵是 true
/*
 * 這里的 true 不是字符串,而是 boolean。
 * 同樣,未被引號(hào)包裹的 null、false、數(shù)字都是對(duì)應(yīng)類型的數(shù)據(jù),而不是字符串
 * 其他符合變量命名規(guī)則的鍵都是普通字符串,被單引號(hào)或雙引號(hào)包裹的也是
 */
RunnerUtil.run(" {'true': 'value', 25: false, 'name': \"張三\"}");

運(yùn)算支持的類型:

普通四則混合運(yùn)算:+、-、*、/、%、()
RunnerUtil.run(" 1 + 1 "); // 2
RunnerUtil.run(" 1 + (3 * 4)) "); // 13
RunnerUtil.run(" 'Hello ' + \"World!\" "); // "Hello World!"
RunnerUtil.run(" true + false "); // "truefalse"
/*
 * true+false 在 Java 中是不允許的
 * 但如果是“+”運(yùn)算的話,這里均作為普通字符串;
 * 相當(dāng)于調(diào)用了 toString 方法
 */

位運(yùn)算:&、|、^、<<、>>
RunnerUtil.run(" 1 ^ 1 "); 
RunnerUtil.run(" 1 & 1 "); 
RunnerUtil.run(" 1 | 1 "); 
RunnerUtil.run(" 1 << 1 "); 
RunnerUtil.run(" 1 >> 1 ");

比較運(yùn)算:>、>=、==、<=、<
RunnerUtil.run(" 1 + 1 == 2 "); // true
RunnerUtil.run(" 1 + 1 < 2 "); // false

邏輯運(yùn)算:&&、||、!
RunnerUtil.run("1+1==2 && 5 > 4"); // true

變量:命名規(guī)則與 Java 變量命名規(guī)則相同,同時(shí) null、true、false 不能作為變量
表達(dá)式中包含變量就代表這個(gè)表達(dá)式在運(yùn)行得到結(jié)果時(shí)需要從外部獲取數(shù)據(jù),如果不能正確的從數(shù)據(jù)源讀取到數(shù)據(jù),運(yùn)行就會(huì)拋出異常;

RunnerUtil.run(" 'Hello, ' + name "); // 拋出異常

Map data = new HashMap();
data.put("name", "Li Lei!");

RunnerUtil.run(" 'Hello, ' + name ", data); // "Hello, Li Lei!"

鏈?zhǔn)饺≈担烘準(zhǔn)秸Z(yǔ)法與 JavaScript 很相似

HashMap data = new HashMap(); 

ArrayList list = new ArrayList(); 
list.add(true); 
list.add(false); 
list.add(25); 
list.add('隔壁老王'); 

HashMap map = new HashMap(); 
map.put("name", "小四"); 
map.put("index", 2); 
map.put(true, "true 是 Boolean 類型作為鍵"); 

data.put("list", list); 
data.put("map", map); 

RunnerUtil.run("map.name", data); // "小四"

RunnerUtil.run("map['name']", data); 
// "小四" (也可以這樣取值)

RunnerUtil.run("list[ 2 ]", data);
// 25 (索引取值需要用方括號(hào)包裹) 

RunnerUtil.run("list[3]", data);
// "隔壁老王" (索引取值需要用方括號(hào)包裹) 

RunnerUtil.run("list[map.index]", data); // 25
// (這是高級(jí)點(diǎn)的用法,方括號(hào)包含另一個(gè)表達(dá)式
// 返回值是一個(gè)索引,然后返回索引指向的值)

RunnerUtil.run("[true]", data); // "true 是 Boolean 類型作為鍵"
// 如果不用方括號(hào)包括,true 就是一個(gè)直接值,返回 true
// 那么問(wèn)題來(lái)了:
// 如果傳入的數(shù)據(jù)不是 Map 或 POJO,而是 List 或數(shù)組怎么辦呢?
RunnerUtil.run(" [1] ", list); // false
// 啊……唐宗宋祖,略顯風(fēng)騷!

// 這種鏈?zhǔn)秸Z(yǔ)法與 JavaScript 很相似

運(yùn)行方法:目前只能運(yùn)行無(wú)參和一個(gè)參數(shù)的方法,變長(zhǎng)參數(shù)的方法支持不完善,慎用。
這里的數(shù)據(jù) data 繼續(xù)用上一條的 data,具體數(shù)據(jù)不寫了

RunnerUtil.run("map.size()", data); // 3
RunnerUtil.run("map.get('name')", data); // "小四" 
RunnerUtil.run("map.get('name').length()", data); // 2
RunnerUtil.run("map.name.length()", data); // 2
RunnerUtil.run(" [3].length() ", list); // 4
// 唐宗宋祖,又顯風(fēng)騷!

運(yùn)行靜態(tài)方法: @ ;運(yùn)行靜態(tài)方法需要用到“@”符號(hào)作為標(biāo)記。目前也不支持多參數(shù)方法調(diào)用。
當(dāng)你打開源碼會(huì)發(fā)現(xiàn)這是一整個(gè)獨(dú)立的工具庫(kù),很多方法和 commons-lang 包內(nèi)容相似(個(gè)人認(rèn)為不是重復(fù)造輪子,也有很多不同的和不如的)...,運(yùn)行靜態(tài)方法也可以運(yùn)行這個(gè)工具庫(kù)內(nèi)的所有工具方法,暫時(shí)未將 RunnerUtil 剝離出來(lái),也還不支持自定義的靜態(tài)方法調(diào)用,不過(guò)這個(gè)工具庫(kù)所提供的功能

RunnerUtil.run("@System.currentTimeMillis() ");
// 15.....(一個(gè)毫秒數(shù))
RunnerUtil.run("@Objects.toString(25) "); // "25"

綜上,就是這個(gè)工具庫(kù)所支持的字符串表達(dá)式運(yùn)算了,以上所列舉的運(yùn)算可以嵌套、連接、但是不能交叉的進(jìn)行運(yùn)算。接下來(lái)要做的是加入的功能是多參數(shù)方法調(diào)用,希望對(duì)大家的日常開發(fā)有所幫助,也希望大家給點(diǎn)意見,如出現(xiàn) BUG 一定在最快的時(shí)間內(nèi)修改,謝謝大家啦啦啦!!

總結(jié)

以上所述是小編給大家介紹的Java 中運(yùn)行字符串表達(dá)式的方法,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java那些鮮為人知的關(guān)鍵字volatile詳析

    Java那些鮮為人知的關(guān)鍵字volatile詳析

    這篇文章主要給大家介紹了關(guān)于Java那些鮮為人知的關(guān)鍵字volatile的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Java經(jīng)典算法匯總之冒泡排序

    Java經(jīng)典算法匯總之冒泡排序

    冒泡排序基本思想:在要排序的一組數(shù)中,對(duì)當(dāng)前還未排好序的范圍內(nèi)的全部數(shù),自上而下對(duì)相鄰的兩個(gè)數(shù)依次進(jìn)行比較和調(diào)整,讓較大的數(shù)往下沉,較小的往上冒。即:每當(dāng)兩相鄰的數(shù)比較后發(fā)現(xiàn)它們的排序與排序要求相反時(shí),就將它們互換。
    2016-04-04
  • 如何為?Spring?Boot?項(xiàng)目配置?Logback?日志

    如何為?Spring?Boot?項(xiàng)目配置?Logback?日志

    由于?Spring?Boot?的默認(rèn)日志框架選用的?Logback,再加上?Log4j2?之前爆過(guò)嚴(yán)重的漏洞,所以我們這次就只關(guān)注?Logback,本文重點(diǎn)給大家介紹如何為?Spring?Boot?項(xiàng)目配置?Logback?日志,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • ReentrantLock可重入鎖原理解析

    ReentrantLock可重入鎖原理解析

    這篇文章主要為大家介紹了ReentrantLock可重入鎖原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Spring Security基本原理詳解

    Spring Security基本原理詳解

    這篇文章主要介紹了Spring Security基本原理詳解,springsecurity底層實(shí)現(xiàn)為一條過(guò)濾器鏈,就是用戶請(qǐng)求進(jìn)來(lái),判斷有沒有請(qǐng)求的權(quán)限,拋出異常,重定向跳轉(zhuǎn),需要的朋友可以參考下
    2023-05-05
  • java連接數(shù)據(jù)庫(kù)增、刪、改、查工具類

    java連接數(shù)據(jù)庫(kù)增、刪、改、查工具類

    這篇文章主要介紹了java連接數(shù)據(jù)庫(kù)增、刪、改、查工具類,需要的朋友可以參考下
    2014-05-05
  • 詳解JAVA Spring 中的事件機(jī)制

    詳解JAVA Spring 中的事件機(jī)制

    這篇文章主要介紹了JAVA Spring 中的事件機(jī)制的相關(guān)資料,文中示例代碼非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Spring如何使用@Indexed加快啟動(dòng)速度

    Spring如何使用@Indexed加快啟動(dòng)速度

    這篇文章主要介紹了Spring如何使用@Indexed加快啟動(dòng)速度,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java如何讀取properties文件將參數(shù)值配置到靜態(tài)變量

    java如何讀取properties文件將參數(shù)值配置到靜態(tài)變量

    這篇文章主要介紹了java如何讀取properties文件將參數(shù)值配置到靜態(tài)變量問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Spring條件注解用法案例分析

    Spring條件注解用法案例分析

    這篇文章主要介紹了Spring條件注解用法,結(jié)合具體實(shí)例形式分析了Spring條件注解相關(guān)原理、使用方法及操作注意事項(xiàng),需要的朋友可以參考下
    2019-11-11

最新評(píng)論