Jep的简单使用(解析和评估数学表达式)
Jep Java 只需几行代码就可以解析和评估数学表达式。该软件包允许您的用户以字符串形式输入公式,并立即对其进行评估。Jep 支持用户定义的变量、常量和函数。包括许多常见的数学函数和常数。
最近在做项目的时候多处使用到了数学表达式的计算,故寻找了一个比较有意思的工具类,方便的实现了对表达式的封装。
@SpringBootTest
class MyWebApplicationTests {
@Test
void contextLoads() throws Exception {
UserModel userModel = new UserModel();
UserModel userModel1 = userModel.builder().age(18).id(1L).build();
String exp = "(age * (age + 10))/age";
Object resultAdvanced = MathFormulaUtil.getResultAdvanced(userModel1, exp);
System.out.println(resultAdvanced);
}
}
class MathFormulaUtil {
/** * GET 新技能 * @param obj 目标对象 里面封装了数据 * @param exp 表达式 * @return 计算结果 * @throws Exception 异常 */
@SuppressWarnings({"rawtypes"})
public static Object getResultAdvanced(Object obj,String exp) throws Exception{
Object result = null; //算术结果
try {
//核心对象
JEP jep = new JEP();
//获取目标对象的 属性名 和 属性值组成的Map对象,然后Map对象组成List
List fieldsLists = getFiledsInfo(obj);
//循环一次取出 List 中的 Map 中的 key - value
for (Object listObj : fieldsLists) {
//获取属性名称
String fieldName = String.valueOf(((Map) listObj).get("name"));
//获取属性的值
Object fieldValue = getFieldValueByName(fieldName, obj);
if(fieldValue != null && !fieldValue.toString().isEmpty()){ //保证非空
//添加变量 动态赋值
jep.addVariable(fieldName, Double.parseDouble(String.valueOf(fieldValue)));
}
}
//解析
jep.parseExpression(exp);
//计算结果
result = jep.getValue();
} catch (Exception e) {
System.err.println("表达式中所含的字段 在实体类中没有赋予相应的值");
}
//返回结果
return result;
}
/** * 根据属性名获取属性值 * @param fieldName 变量名 * @param o 对象 * @throws Exception 异常 * * @author 杨润康 * */
private static Object getFieldValueByName(String fieldName, Object o) throws Exception {
//构造get方法名
String getter = "get" + firstAlpUpCase(fieldName);
//获取方法
Method method = o.getClass().getMethod(getter, new Class[] {});
//取值
Object value = method.invoke(o, new Object[] {});
return value;
}
/**
*
* 获取 属性名(name),属性值(value)的map组成的list
* @param 目标对象
* @return 封装了 属性-值 的Map 组成的 List 集合
* @throws Exception 异常
*
* @author 杨润康
*
*/
@SuppressWarnings({ "unused", "rawtypes", "unchecked" })
private static List getFiledsInfo(Object o) throws Exception{
//获取定义的变量
Field[] fields=o.getClass().getDeclaredFields();
//变量名数组
String[] fieldNames=new String[fields.length];
List list = new ArrayList();
Map infoMap=null;
for(int i=0;i<fields.length;i++){
if (Modifier.isStatic(fields[i].getModifiers())) {
continue;
}
infoMap = new HashMap();
//获取变量名
infoMap.put("name", fields[i].getName());
//变量名对应的值
infoMap.put("value", getFieldValueByName(fields[i].getName(), o));
//存入集合
list.add(infoMap);
}
return list;
}
/** * 字符串首字母大写 * @param nodeName 节点名称 * @return 首字母大写的字符串 * * @author 杨润康 */
public static String firstAlpUpCase(String nodeName) {
String s = nodeName.substring(0,1);
Pattern p = Pattern.compile("[a-z]");
Matcher m = p.matcher(s);
if(m.matches()){
char[] cs=nodeName.toCharArray();
cs[0]-=32;
return String.valueOf(cs);
}
return nodeName;
}
}
注意事项
如果使用了lombok,大家都清楚lombok boolean类型的参数存在序列化的问题,故在定义boolean类型的时候使用Boolean引用数据类型来定义