【Java 开发实例】Java 直接根据日常字符串公式来计算得到数据

347 阅读3分钟

提前说明:此方法工具类使用范围:① 简单的公式计算;② 不要求数据高精度;③ 数据值最大圈定为(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]

优化

如果需要使用大整数且保证数据的高精度,可以自定义接口实现简单的公式计算器的功能。