[Java代码] java数学表达式计算 QLExpress

本文介绍如何使用Java来解析和计算QLExpress格式的数学表达式,详细讲解了相关算法和步骤,帮助读者理解如何处理复杂数学计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

北风网AD

你想知道 a love b = ? 吗 ,你想随意定义自己的操作符号吗 ? 请使用 QLExpress工具包
这个表达式相对别的计算工具,优点主要体现在:
A、不需要预先加载可能需要的所有属性值
B、 用户可以根据业务需要自定义操作符号和函数 
C、可以同步输出判断错误信息,有利于提高业务系统在规则判断等使用场景下的用户体验。减少业务系统相关的处理代码。

主要用途:一些业务规则的组合判断,同时需要输出相关的错误信息

执行的流程:
1、单词分解
2、语法分析

最简单Hello范例:

String express = "10 * 10 + 1 + 2 * 3 + 5 * 2";
ExpressRunner runner = new ExpressRunner();
Object result = runner.execute(express, null, false, null);
System.out.println("表达式计算:" + express + " = " + result);

其它范例:
ExpressRunner runner = new ExpressRunner();
runner.addOperator("love", new LoveOperator("love"));
runner.addOperatorWithAlias("属于", "in", "用户$1不在允许的范围");
runner.addOperatorWithAlias("myand", "and", "用户$1不在允许的范围");
runner.addFunction("累加", new GroupOperator("累加"));
runner.addFunction("group", new GroupOperator("group"));
runner.addFunctionOfClassMethod("isVIP", BeanExample.class.getName(),
"isVIP", new String[] { "String" }, "$1不是VIP用户");
runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs",
new String[] { "double" }, null);
runner.addFunctionOfClassMethod("转换为大写", BeanExample.class.getName(),
"upper", new String[] { "String" }, null);

在这个计算引擎里面, 执行下述表达式结果:
Example 0 : System.out.println("ss") = null
Example 1 : unionName = new com.ql.util.express.test.BeanExample("张三").unionName("李四") = 张三-李四
Example 2 : group(2,3,4) = 9
Example 3 : 取绝对值(-5.0) = 5.0
Example 4 : max(2,3,4,10) = 10
Example 5 : max(3,2) + 转换为大写("abc") = 3ABC
Example 6 : c = 1000 + 2000 = 3000
Example 7 : b = 累加(1,2,3)+累加(4,5,6) = 21
Example 8 : 三星卖家 and 消保用户 = true
Example 9 : 'a' love 'b' love 'c' love 'd' = d{c{b{a}b}c}d
Example 10 : 10 * 10 + 1 + 2 * 3 + 5 * 2 = 117
Example 11 : ( (1+1) 属于 (4,3,5)) and isVIP("玄难") = false
系统输出的错误提示信息:[用户 2 不在允许的范围, 玄难 不是VIP用户]


表达式支持概述:
1、基本的java语法:
A、四则运算 : 10 * 10 + 1 + 2 * 3 + 5 * 2
B、boolean运算: 3 > 2 and 2 > 3
C、创建对象,对象方法调用,静态方法调用:new com.ql.util.express.test.BeanExample("张三").unionName("李四")
D、变量赋值:a = 3 + 5
F、支持 in,max,min: (a in (1,2,4)) and (b in("abc","bcd","efg"))
2、提供表达式上下文,属性的值不需要在初始的时候全部加入,
而是在表达式计算的时候,需要什么信息才通过上下文接口获取 
避免因为不知道计算的需求,而在上下文中把可能需要的数据都加入。
runner.execute("三星卖家 and 消保用户",errorList,true,expressContext)
"三星卖家"和"消保用户"的属性是在需要的时候通过接口去获取。
3、可以将计算结果直接存储到上下文中供后续业务使用。例如:
runner.execute("c = 1000 + 2000",errorList,true,expressContext);
则在expressContext中会增加一个属性c=3000,也可以在expressContext实现直接的数据库操作等。
4、 可以将类和Spring对象的方法映射为表达式计算中的别名,方便其他业务人员的立即和配置。例如:
将 Math.abs() 映射为 "取绝对值"。 则 "取绝对值(-5.0)" = "5.0"
runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs",new String[] { "double" }, null);
5、可以为已经存在的boolean运算操作符号设置别名,增加错误信息同步输出,在计算结果为false的时候,同时返回错误信息。例如:
runner.addOperatorWithAlias("属于", "in", "用户$1不在允许的范围")。
用户自定义的函数同样也可以设置错误信息:例如:
runner.addFunctionOfClassMethod("isOk", BeanExample.class.getName(),"isOk", new String[] { "String" }, "$1 不是VIP用户");

则在调用List errorList = new ArrayList();
Object result =runner.execute("( (1+1) 属于 (4,3,5)) and isOk("玄难")",errorList,true,null);
执行结果 result = false.同时在errorList中还会返回2个错误原因:
1、"用户 2 不在允许的范围",2、玄难 不是VIP用户 
这在业务系统需要进行规则计算,同时需要返回

6、可以自定义计算函数。例如:
自定一个操作函数 group:
class GroupOperator extends Operator {
public GroupOperator(String aName) {
this.name= aName;
}
public Object executeInner(Object[] list)throws Exception {
Object result = new Integer(0);
for (int i = 0; i < list.length; i++) {
result = OperatorOfNumber.Add.execute(result, list[i]);
}
return result;
}
}
然后增加到运算引擎:
runner.addFunction("累加", new GroupOperator("累加"));
runner.addFunction("group", new GroupOperator("group"));
则 执行:group(2,3,4) = 9 ,累加(1,2,3)+累加(4,5,6)=21
7、可以自定义新的操作符号 。自定义的操作符号优先级设置为最高。例如 :
自定一个操作函数 love:
class LoveOperator extends Operator { 
public LoveOperator(String aName) {
this.name= aName;
}
public Object executeInner(Object[] list)
throws Exception {
String op1 = list[0].toString();
String op2 = list[1].toString();
String result = op2 +"{" + op1 + "}" + op2; 
return result;
}
}
然后增加到运算引擎:
runner.addOperator("love", new LoveOperator("love"));
则 执行:'a' love 'b' love 'c' love 'd' = "d{c{b{a}b}c}d"
8、运算引擎在没有预编译的情况下, 执行10万次 "10 * 10 + 1 + 2 * 3 + 5 * 2" 耗时:3.187秒
runner.execute("10 * 10 + 1 + 2 * 3 + 5 * 2", null, false,null);
在打开 预编译缓存开关的情况下, 执行10万次 "10 * 10 + 1 + 2 * 3 + 5 * 2" 耗时: 0.171秒
runner.execute("10 * 10 + 1 + 2 * 3 + 5 * 2", null, true,null); 
运行引擎是线程安全的。在业务系统中实际使用过程中应该打开缓存预编译的开关,性能会更加。
可以调用clearExpressCache()清除缓存 。
在开启开关的情况下,会缓存解析后的最后执行指令如下所示,
避免了字符串解析、词法分析、语法分析等步骤,简单对比一下,会提高30倍的速度:
1:LoadData 10
2:LoadData 10
3:OP : * OPNUMBER[2] 
4:LoadData 1
5:OP : + OPNUMBER[2] 
6:LoadData 2
7:LoadData 3
8:OP : * OPNUMBER[2] 
9:OP : + OPNUMBER[2] 
10:LoadData 5
11:LoadData 2
12:OP : * OPNUMBER[2] 
13:OP : + OPNUMBER[2] 
9、这个表达式相对别的计算工具,有点主要体现在:
A、不需要预先加载可能需要的所有属性值
B、 用户可以根据业务需要自定义操作符号和函数 
C、可以同步输出判断错误信息,有利于提高业务系统在规则判断等使用场景下的用户体验。减少业务系统相关的处理代码。
10、后续可以进一步优化的地方:
A、现有的单词拆解、词法分析、语法分析都是自己写的山寨版,可以利用其他成熟的开源工具。
B、优化具体的操作指令,提高单个操作符号的运行效率
C、经过简单的扩展支持自定义代码片段的运行。 


http://www.lzfsk.com/fkjb/ydy/8080.html

http://www.lzfsk.com/fkjb/ydy/8081.html
http://www.lzfsk.com/fkjb/ydy/8082.html
http://www.lzfsk.com/fkjb/ydy/8084.html
http://www.lzfsk.com/fkjb/ydy/8085.html
### QLExpress 表达式用法与示例 QLExpress 是一个强大的表达式解析引擎,支持复杂的业务逻辑和动态计算。以下是关于 QLExpress 表达式的语法、使用方法及示例的详细介绍。 #### 1. 基本语法 QLExpress 支持标准的数学运算符和逻辑运算符,包括但不限于加减乘除 (`+`, `-`, `*`, `/`) 和比较运算符 (`>`, `<`, `==`, `!=`, `>=`, `<=`)。此外,还支持条件判断语句(如 `if-then-else`)以及函数调用[^1]。 ```java // 示例:简单的数学运算 String express = "a + b * c"; DefaultContext<String, Object> context = new DefaultContext<>(); context.put("a", 1); context.put("b", 2); context.put("c", 3); Object result = runner.execute(express, context, null, true, false); System.out.println("表达式结果: " + result); // 输出:7 ``` #### 2. 条件判断 QLExpress 支持嵌套的 `if-then-else` 结构,允许在表达式中实现复杂的业务逻辑[^5]。 ```java String expression = "if (city == 1 and age > 70 and sex == 1) then {return 33;} else {return 0;}"; Map<String, Object> params = new HashMap<>(); params.put("city", 1); params.put("age", 78); params.put("sex", 1); Object result = runner.execute(expression, params, null, true, false); System.out.println("结果: " + result); // 输出:33 ``` #### 3. 宏定义 宏定义是 QLExpress 的一个重要特性,通过将复杂的表达式片段定义为宏,可以在多个地方复用,从而提高代码的可读性和维护性[^3]。 ```java runner.addMacro("计算平均成绩", "(语文 + 数学 + 英语) / 3.0"); runner.addMacro("是否优秀", "计算平均成绩 > 90"); DefaultContext<String, Object> context = new DefaultContext<>(); context.put("语文", 88); context.put("数学", 99); context.put("英语", 95); Object result = runner.execute("是否优秀", context, null, false, false); System.out.println("Result: " + result); // 输出:false ``` #### 4. 实际应用案例 以下是一个实际场景中的应用示例,展示如何使用 QLExpress 计算折扣后的金额[^4]。 ```java DefaultContext<String, Object> context = new DefaultContext<>(); context.put("amount", 1000); context.put("discount", 0.1); String expression = "amount * (1 - discount)"; Object result = runner.execute(expression, context, null, true, false); System.out.println("Result: " + result); // 输出:900.0 ``` #### 5. 编译脚本查询 QLExpress 还支持编译脚本以查询外部需要定义的变量和函数,适用于更复杂的业务场景。 ```java String script = "function calculateDiscount(price, discountRate) { return price * (1 - discountRate); }"; runner.compile(script); DefaultContext<String, Object> context = new DefaultContext<>(); context.put("price", 200); context.put("discountRate", 0.2); Object result = runner.execute("calculateDiscount(price, discountRate)", context, null, true, false); System.out.println("Result: " + result); // 输出:160.0 ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值