前言
我们都知道,java中对大小数,高精度的计算都会用到bigdecimal.但是在实际应用中,运用bigdecimal还是会遇到一些问题,下面话不多说了,来一起看看详细的介绍吧
问题描述:
程序中需要判断一个字段是否为0(字段类型为bigdecimal),想都没想,对象的判断用equals?结果却与预期有一定的差距,看下面代码及运行结果。
|
1
2
3
4
5
|
public static void main(string[] args) {
bigdecimal decimal1 = bigdecimal.valueof(0);
bigdecimal decimal2 = new bigdecimal("0.00");
system.out.println("the result is " +decimal1.equals(decimal2));
}
|
运行结果:
the result is false
结论: bigdecimal类型比较相等不能简单的通过equals方法实现。
bigdecimal类的equals方法源码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public boolean equals(object x) {
if (!(x instanceof bigdecimal))
return false;
bigdecimal xdec = (bigdecimal) x;
if (x == this)
return true;
if (scale != xdec.scale)//这里会比较数字的精度
return false;
long s = this.intcompact;
long xs = xdec.intcompact;
if (s != inflated) {
if (xs == inflated)
xs = compactvalfor(xdec.intval);
return xs == s;
} else if (xs != inflated)
return xs == compactvalfor(this.intval);
return this.inflate().equals(xdec.inflate());
}
|
看上面的注释可以知道,bigdecimal类的equals方法会判断数字的精度,看下面的代码及运行结果:
|
1
2
3
4
5
|
public static void main(string[] args) {
bigdecimal decimal1 = bigdecimal.valueof(0).setscale(2);
bigdecimal decimal2 = new bigdecimal("0.00").setscale(2);
system.out.println("the result is " +decimal1.equals(decimal2));
}
|
运行结果:
the result is true
结论: 使用bigdecimal类equals方法判断两个bigdecimal类型的数据时,需要设置精度,否则结果可能不正确。
思考:每次都设置精度比较麻烦,有其他方式进行相等的比较吗?
看了下bigdecimal的方法列表,有一个名为compareto的方法,通过注释可知,貌似可以进行不同精度的比较,看下面的代码。
|
1
2
3
4
5
|
public static void main(string[] args) {
bigdecimal decimal1 = bigdecimal.valueof(1.1);
bigdecimal decimal2 = new bigdecimal("1.10");
system.out.println("the result is " +decimal1.compareto(decimal2));
}
|
运行结果:
the result is 0
0表示两个数相等,所有可以通过compareto实现不同精度的两个bigdecimal类型的数字是否相等的比较
引出的问题:公司的项目中,为了避免由于精度丢失引起问题,凡是有精度要求的字段用的都是bigdecimal类型。数据持久层用的是mybatis框架,mybatis的mapper文件中有些条件判断用的是bigdecimal对应的字段,如下:
|
1
2
3
4
5
6
|
<select id="selectbycondition" resulttype="com.scove.demo.domain.score">
select * from tb_score where 1=1
<if test="score!=null and score!=0">
and score>#{score}
</if>
...
|
score是一个bigdecimal类型的字段,score!=0 mybatis是如何进行判断的,会不会用的是上面的equals方法?如果是那么项目上线会不会捅大篓子,想到这儿,有点怕了。写了个程序测了下,这样写完全没问题,能够达到我想要的目的。但是还是有点担心,看看mybatis底层是如何实现的吧,以免以后犯类似的错误嘛。
经过分析调试,很快就找到了关键代码的位置,如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class expressionevaluator {
public boolean evaluateboolean(string expression, object parameterobject) {
object value = ognlcache.getvalue(expression, parameterobject);
if (value instanceof boolean) {
return (boolean) value;
}
if (value instanceof number) {
return !new bigdecimal(string.valueof(value)).equals(bigdecimal.zero);
}
return value != null;
}
...
|
|
1
2
3
4
5
6
7
8
9
10
11
|
public final class ognlcache {
....
public static object getvalue(string expression, object root) {
try {
map<object, ognlclassresolver> context = ognl.createdefaultcontext(root, new ognlclassresolver());
return ognl.getvalue(parseexpression(expression), context, root);
} catch (ognlexception e) {
throw new builderexception("error evaluating expression '" + expression + "'. cause: " + e, e);
}
}
|
用的是表达式求值,ognl这个类的竟然没有源码,apache的官网上找了下,是有相应的源码的,只是需要单独下载,真麻烦,算了不看了。据说底层用的是spring 的ognl表达式,我也不 关心了。但是以后如果不确定mapper中的test是否正确咋个办?
想了下,还是写一个工具类在拿不准的时候用一下吧,反正拿不准的时候肯定很少,所以随便写了简单的吧,如下:
|
1
2
3
4
5
6
7
8
|
public static void main(string[] args) {
expressionevaluator evaluator = new expressionevaluator();
string expression = "score!=null and score!=0";
dynamiccontext context = new dynamiccontext(new configuration(), null);
context.bind("score", bigdecimal.valueof(0.1));
boolean flag = evaluator.evaluateboolean(expression , context.getbindings());
system.out.println("the result is " +flag);
}
|
运行结果:
the result is true
总结
开发过程中,一定要细心去处理细节上的东西,不然一不小心就跳坑里了,轻则系统造成数据的不一致,修复数据;重则造成重大的损失….
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对快网idc的支持。
原文链接:https://www.cnblogs.com/falco/p/9500833.html
相关文章
- ASP.NET本地开发时常见的配置错误及解决方法? 2025-06-10
- ASP.NET自助建站系统的数据库备份与恢复操作指南 2025-06-10
- 个人网站服务器域名解析设置指南:从购买到绑定全流程 2025-06-10
- 个人网站搭建:如何挑选具有弹性扩展能力的服务器? 2025-06-10
- 个人服务器网站搭建:如何选择适合自己的建站程序或框架? 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
2025-05-27 62
-
创建个人或企业网站:租用虚拟专用服务器(VPS)还是物理服务器?
2025-06-05 58 -
2025-05-25 69
-
2025-05-25 57
-
2025-05-25 98

