java執(zhí)行字符串公式的三種方法總結(jié)
問(wèn)題描述
最近,在項(xiàng)目中遇到了一項(xiàng)特定需求:前端用戶(hù)需要輸入一個(gè)數(shù)學(xué)公式,這個(gè)公式隨后被保存到后臺(tái)數(shù)據(jù)庫(kù)中。當(dāng)后臺(tái)需要從數(shù)據(jù)庫(kù)中檢索這個(gè)公式并進(jìn)行計(jì)算時(shí),面臨的一個(gè)挑戰(zhàn)是,從數(shù)據(jù)庫(kù)獲取的公式是以字符串形式存在的,無(wú)法直接代入數(shù)值進(jìn)行計(jì)算。
解決方案
方法1:使用 ScriptEngine(Java內(nèi)置)
經(jīng)查閱資料,發(fā)現(xiàn)利用Java的腳本引擎(特別是JavaScript引擎)能夠高效地解析并執(zhí)行各類(lèi)數(shù)學(xué)公式。在JDK 1.6及更高版本中,引入了javax.script包,這一包為開(kāi)發(fā)者提供了極大的便利,能夠輕松地將腳本引擎嵌入到Java應(yīng)用程序中。借助這一功能,我們可以無(wú)縫地處理字符串形式的公式,并將其轉(zhuǎn)化為可執(zhí)行的代碼,從而滿(mǎn)足項(xiàng)目中的計(jì)算需求。
具體代碼:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class EvaluateExpression {
public static void main(String[] args) {
// 示例公式字符串(從數(shù)據(jù)庫(kù)中獲取)
String expression = "3 + 5 * (2 - 8)";
// 創(chuàng)建一個(gè)腳本引擎管理器
ScriptEngineManager manager = new ScriptEngineManager();
// 獲取一個(gè)JavaScript引擎
ScriptEngine engine = manager.getEngineByName("JavaScript");
try {
// 執(zhí)行公式并獲取結(jié)果
Object result = engine.eval(expression);
// 將結(jié)果轉(zhuǎn)換為字符串并打印
System.out.println("公式" + expression + "的執(zhí)行結(jié)果是:"+ result);
} catch (ScriptException e) {
// 捕獲并處理腳本異常
System.err.println(e.getMessage());
}
}
}
運(yùn)行結(jié)果

注:如果公式中包含變量作為運(yùn)算的一部分,我們可以通過(guò)使用Java字符串的replace()或者replaceAll()方法,將這些變量替換為具體的數(shù)值,隨后再進(jìn)行計(jì)算。以下是一個(gè)具體的代碼實(shí)現(xiàn)示例,用于說(shuō)明這一過(guò)程:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class EvaluateExpression {
public static void main(String[] args) {
// 示例公式字符串(從數(shù)據(jù)庫(kù)中獲取)
String expression = "3 + a * (2 - b) + a";
// 創(chuàng)建一個(gè)腳本引擎管理器
ScriptEngineManager manager = new ScriptEngineManager();
// 獲取一個(gè)JavaScript引擎
ScriptEngine engine = manager.getEngineByName("JavaScript");
String a = "5", b = "8";
try {
// 執(zhí)行公式并獲取結(jié)果
Object result = engine.eval(expression.replaceAll("a", a).replace("b", b));
// 將結(jié)果轉(zhuǎn)換為字符串并打印
System.out.println("公式" + expression + "的執(zhí)行結(jié)果是:"+ result);
} catch (ScriptException e) {
// 捕獲并處理腳本異常
System.err.println(e.getMessage());
}
}
}
運(yùn)行結(jié)果

注意:Java 9+ 已將 Nashorn 引擎標(biāo)記為廢棄(需手動(dòng)添加依賴(lài)),且存在安全風(fēng)險(xiǎn)。建議對(duì)非受信輸入進(jìn)行嚴(yán)格校驗(yàn)。
方法2:使用第三方庫(kù) [exp4j](推薦)
官網(wǎng)地址: exp4j
適用于數(shù)學(xué)表達(dá)式(安全且輕量級(jí)):
- 添加依賴(lài)(Maven):
<dependency>
<groupId>net.objecthunter</groupId>
<artifactId>exp4j</artifactId>
<version>0.4.8</version>
</dependency>
- 示例代碼:
import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;
public class FormulaCalculator {
public static void main(String[] args) {
String formula = "10 * (3 + 2) / 5";
Expression expression = new ExpressionBuilder(formula).build();
double result = expression.evaluate();
System.out.println(result); // 輸出: 10.0
}
}
優(yōu)勢(shì):
- 無(wú)外部依賴(lài),避免代碼注入風(fēng)險(xiǎn)
- 支持自定義變量(如
"x^2 + y") - 支持?jǐn)?shù)學(xué)函數(shù)(
sin,log等)
方法3:使用Expression(Spring框架)(推薦)
適用于 Spring 項(xiàng)目:
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
public class FormulaCalculator {
public static void main(String[] args) {
String formula = "10 * (3 + 2) / 5";
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(formula);
Integer result = exp.getValue(Integer.class);
System.out.println(result); // 輸出: 10
}
}
總結(jié)
javax.script包中的ScriptEngineManager腳本引擎管理器是一個(gè)功能強(qiáng)大的工具,它能夠滿(mǎn)足我們?cè)贘ava代碼中執(zhí)行字符串公式的需求。通過(guò)ScriptEngineManager,我們可以輕松地獲取到各種腳本引擎(如JavaScript引擎),并利用這些引擎來(lái)解析和執(zhí)行嵌入在字符串中的數(shù)學(xué)表達(dá)式或其他類(lèi)型的腳本代碼。這種方法不僅簡(jiǎn)化了代碼的實(shí)現(xiàn),還提高了程序的靈活性和可擴(kuò)展性,使我們能夠高效地處理各種復(fù)雜的計(jì)算任務(wù)。
雖然ScriptEngine能滿(mǎn)足需求,但對(duì)Java 9+兼容性較差??紤]到目前大多數(shù)企業(yè)都采用Spring全家桶進(jìn)行開(kāi)發(fā),我們強(qiáng)烈推薦使用Spring Expression。當(dāng)然exp4j也是很不錯(cuò)的選擇。
到此這篇關(guān)于java執(zhí)行字符串公式的三種方法的文章就介紹到這了,更多相關(guān)java執(zhí)行字符串公式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot集成Spring Cloud Security進(jìn)行安全增強(qiáng)的方法
Spring Cloud Security是Spring Security的擴(kuò)展,它提供了對(duì)Spring Cloud體系中的服務(wù)認(rèn)證和授權(quán)的支持,包括OAuth2、JWT等,這篇文章主要介紹了Spring Boot集成Spring Cloud Security進(jìn)行安全增強(qiáng),需要的朋友可以參考下2024-11-11
Oracle+Mybatis的foreach insert批量插入報(bào)錯(cuò)的快速解決辦法
本文給大家介紹Oracle+Mybatis的foreach insert批量插入報(bào)錯(cuò)的快速解決辦法,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友參考下吧2016-08-08
SpringBoot中使用異步調(diào)度程序的高級(jí)方法
本文主要介紹了SpringBoot中使用異步調(diào)度程序的高級(jí)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07
Java多線(xiàn)程之Callable接口的實(shí)現(xiàn)
這篇文章主要介紹了Java多線(xiàn)程之Callable接口的實(shí)現(xiàn),Callable和Runnbale一樣代表著任務(wù),區(qū)別在于Callable有返回值并且可以?huà)伋霎惓?。感興趣的小伙伴們可以參考一下2018-08-08

