提前说明:此方法工具类使用范围:① 简单的公式计算;② 不要求数据高精度;③ 数据值最大圈定为(9999999999999999);
一、完整代码
核心功能:传入一个字符串公式,利用 Java 调用 JavaScript 脚本引擎处理公式得到计算结果。
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
/**
* 展示JDK当前版本的所有脚本引擎
*/
private static void showAllEngines() {
ScriptEngineManager manager = new ScriptEngineManager();
// 得到所有的脚本引擎工厂
List<ScriptEngineFactory> factories = manager.getEngineFactories();
// 这是Java SE 5 和Java SE 6的新For语句语法
for (ScriptEngineFactory factory : factories) {
// 打印脚本信息
System.out.printf("Name: %s%n" +
"Version: %s%n" +
"Language name: %s%n" +
"Language version: %s%n" +
"Extensions: %s%n" +
"Mime types: %s%n" +
"Names: %s%n",
factory.getEngineName(),
factory.getEngineVersion(),
factory.getLanguageName(),
factory.getLanguageVersion(),
factory.getExtensions(),
factory.getMimeTypes(),
factory.getNames());
}
}
/**
* 利用JavaScript来计算公式
* <br/>
* 注意:由于使用的是JavaScript引擎进行的计算,所以在处理大整数数据时将出现数据精确度问题.
*
* @param formula 数学公式(入参值例如: 12-(20*2+8)-(2/3))
* @return 公式计算的结果(结果为:-36.67)
*/
private static String getCalculateResult(String formula) {
ScriptEngineManager manager = new ScriptEngineManager();
// 指定使用 js/JS/JavaScript/javascript 作为处理引擎。
ScriptEngine engine = manager.getEngineByName("js");
Object result;
String calculateResult = null;
// 有效位数
int scale = 2;
try {
result = engine.eval(formula);
if ("Infinity".equals(String.valueOf(result))
|| "undefined".equals(String.valueOf(result))
|| "NaN".equals(String.valueOf(result))) {
return new BigDecimal("0").setScale(scale, RoundingMode.HALF_UP).toString();
}
BigDecimal x = new BigDecimal(result.toString()).setScale(scale, RoundingMode.HALF_UP);
calculateResult = x.toString();
} catch (ScriptException e) {
e.printStackTrace();
}
return calculateResult;
}
private static void testGetCalculateResult() {
// 注意:由于使用的是JavaScript引擎进行的计算,所以在处理大整数数据时将出现数据精确度问题.
List<String> formula = Arrays.asList("0/10", "10/0", "2.55/23.65+((45/2)-(1+2))", "12-(20*2+8)-(2/3)", "10/3", "10-8", "Math.max(12,25)", "1000000000000000000000000000000/3");
for (String s : formula) {
System.out.println(s + "\t" + getCalculateResult(s));
}
// 使用Java的大整数数据类型处理可以保证准确度
BigDecimal num1 = new BigDecimal("1000000000000000000000000000000");
BigDecimal num2 = new BigDecimal("3");
System.out.println("使用大整数计算:" + num1.divide(num2, 6, RoundingMode.HALF_UP).toString()); // 使用大整数计算:333333333333333333333333333333.333333
}
二、结果展示
0/10 0.00
10/0 0.00
2.55/23.65+((45/2)-(1+2)) 19.61
12-(20*2+8)-(2/3) -36.67
10/3 3.33
10-8 2.00
Math.max(12,25) 25.00
// 注意:由于是调用的 JavaScript 去计算公式的,所以不能保证大整数计算的精确度。
1000000000000000000000000000000/3 333333333333333300000000000000.00
// 使用大整数计算
333333333333333333333333333333.333333
// JDK中所有的脚本引擎有:(当前JDK环境下所有的脚本引擎如 Names 所示内容)
Name: Oracle Nashorn // 默认引擎名称
Version: 1.8.0_91 // JDK版本
Language name: ECMAScript // 默认语言(其他的如 js, es 等)
Language version: ECMA - 262 Edition 5.1 // 默认语言版本
Extensions: [js] // 扩展语言为 js
Mime types: [application/javascript, application/ecmascript, text/javascript, text/ecmascript]
Names: [nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript]
优化
如果需要使用大整数且保证数据的高精度,可以自定义接口实现简单的公式计算器的功能。