一个容易被忽视的Java整数溢出错误:无法正确获得年份之差的原因

随着计算机以及编程语言的不断发展,或许我们现在对于各种类型变量的上限已经不如C语言中的那么敏感。例如,int类型(整型)的变量,它的上限值已经远远超过以前C语言中的整型变量的上限。在一个典型的C语言中,int型变量的范围为-32768~32767,而在java中,int型的变量的范围就达到了-2147483648 到2147483647。因此,通常情况下,我们不用考虑溢出问题。但是,最近我在使用java计算时间差的时候,却遇到了一个诡异的错误,经过一段时间的检查,才发现居然是整型溢出的错误。
例如,我们现在打算计算两个时间点的年份之差,虽然有很多的函数能够帮我们解决这个问题(例如,先都取出年份值,再相减)。但是也可以直接通过两个时间点之间的数值差(因为,时间类型的数据在计算机中实际上是以long型的数值来存储的),来计算这种时间差。[b]下面演示的是错误的代码:[/b]
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
Date date = sdf.parse("2008-05-24 00:00:00");
Date date2 = sdf.parse("2009-05-24 00:00:00");
System.out.println((date2.getTime()-date.getTime())/((long)(1000*3600*24*365)));

其中,这段代码的最主要思想就是利用时间点2(date2)的数值,减去时间点1(date)的数值,然后除以1000,将毫秒数值转为秒;再除以3600*24,转为天;最后除以365转成年。代码的逻辑上是没有错误的(当然,严格上来说,应该区分365天或是366天,因而计算年份差是不推荐这么做的),但是执行的时候却总是出错,得到的结果为21!明眼人应该一下子就能够看出这两个时间点的年份差为1年吧。于是考虑将最后一行代码改为如下:
System.out.println((date2.getTime()-date.getTime())/((long)(1000*3600*24)));

发现就能够得到正确的结果:366天。于是再次将代码改为如下:
System.out.println((date2.getTime()-date.getTime())/((long)(1000*3600*24))/365);

发现就能够得到正确的结果了:1年。但是如果将代码又改为第一种情况,就发现还是计算错误。在这种情况下,最有可能的原因就是变量的溢出问题。我们可以计算一下,1年的毫秒数为:
1000*3600*24*365 = 31536000000 ms/year
原来已经远远超过了int型变量的最大值:2147483647了。于是将计算代码改为如下,也能够正确获得结果:
System.out.println((date2.getTime()-date.getTime())/(((long)(3600*24*1000))*((long)(365))));

看来,虽然计算机的支持能力以及编程语言的发展,已经能够然我们很便捷的使用各种变量,但是有时候还是需要注意一下这些类型变量所支持的范围,避免以为超过范围,造成莫名其妙的溢出错误。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值