使用Groovy-Ginq的sum函数计算结果错误,求原因与解决方法
问题分析与修复
问题重现
以下代码执行后,预期计算结果为3.4,但实际得到3.2:
public static final String groovyScript= """ GQ { from o in tuple select sum(o.A) } """; HashMap<String,Double> a = new HashMap<>(); a.put("A",1.6); HashMap<String,Double> b = new HashMap<>(); b.put("A",1.8); ArrayList<Object> tuple = new ArrayList<>(); tuple.add(a); tuple.add(b); GroovyShell groovyShell = new GroovyShell(); groovyShell.setVariable("tuple", tuple); Object result = groovyShell.evaluate(groovyScript);
尝试将HashMap<String,Double>改为HashMap<String,BigDecimal>后,问题依然存在。
原因分析
核心问题出在GQ脚本的sum调用语法错误:
- GQ(Groovy Query)的
sum(o.A)写法不符合其聚合函数的语法规范,这种写法并未正确遍历所有元素的A属性进行累加,反而错误重复计算了第一个元素的值,最终得到1.6*2=3.2。 - 切换为
BigDecimal后,由于语法错误未修正,GQ依然无法正确执行聚合求和,因此问题持续存在。
修复方案
方案1:修正GQ的sum语法
若必须使用GQ框架,需将sum调用改为闭包形式,明确指定聚合的属性:
public static final String groovyScript= """ GQ { from o in tuple select sum{ o.A } } """;
方案2:改用Groovy原生sum方法(更可靠)
放弃GQ语法,直接使用Groovy集合的原生sum方法,避免框架语法限制:
public static final String groovyScript= """ tuple.sum { it.A } """;
补充:BigDecimal的精确使用(可选)
如果需要完全避免浮点数精度问题,使用BigDecimal时必须用字符串构造(直接传入double值仍会引入精度损失):
HashMap<String,BigDecimal> a = new HashMap<>(); a.put("A", new BigDecimal("1.6")); HashMap<String,BigDecimal> b = new HashMap<>(); b.put("A", new BigDecimal("1.8"));
配合Groovy原生sum方法,即可得到精确的3.4结果。
内容的提问来源于stack exchange,提问作者xiaopeng li
相关产品推荐
相关产品推荐

