踩坑了!0作为除数,不一定会抛出异常!原创
你好呀,我是歪歪。
踩坑了啊,又踩坑了啊!
这次踩到一个特别无语的常识坑。知道真相的那一刻,人就是整个麻掉。
先上个代码:
private static double calculate(double a, int b) {
return a / b;
}
你先别问为什么计算不用 BigDecimal,反正程序里面就是有一个类似于这样的方法。
正常用起来也没啥毛病:
注意,我说的是“正常使用看起来没毛病”,不正常使用是怎么样的呢?
看到输出结果是 “Infinity” 的时候,我甚至揉了一下眼睛,以为自己是过于热爱工作,导致用眼过度,看花了。
有一说一,我真没见过这玩意。但是这个单词我认识啊:
在我有限的认知里面, 0 是不可以作为除数的,如果作为除数会抛出异常才对。
但是这个简单的案例打破了我的认知,它不仅没有抛出异常,还给我了一个“无穷大的数”。
在一脸懵逼中,我知道,素材这不就来了嘛。
搜索一番
如果是在使用框架的过程中遇到问题,一般来说我是先自己调试一下,挣扎一波,看看是不是自己的打开方式不对。
但是这个问题太简单了,以至于我甚至找不到调试的角度。
怎么办?
只有直接拿出程序员的祖传技能了:面向浏览器编程。
于是我输入搜索关键字 “Java Infinity”,排在第一的是某博客网站:
我个人是不太喜欢这个网站,所以我按照个人习惯重新搜索了一次:
找到了下面这个链接:
https://www.cnblogs.com/zhisuoyu/p/5314541.html
从这篇文章中我知道了,原来在我的认知里面,0 作为除数会抛出下面这个异常,还有一个前提是“整型运算”:
java.lang.ArithmeticException: / by zero
在 Double 和 Float 里面都定义了“正无穷”和“负无穷”这两个常量:
现在我知道在浮点运算的时候,0 是可以作为除数的。
但是,为什么呢?
Java 里面什么这样设计呢,为什么不一视同仁呢?
博客里面没有写,但是我知道要找到这个问题的答案,这个地方可以去看看:
https://stackoverflow.com/
于是我用 “Java Double Float Infinity” 关键字去查询了一下:
很容易就找到了这个链接:
https://stackoverflow.com/questions/12954193/why-does-division-by-zero-with-floating-point-or-double-precision-numbers-not
这个提问者提出的问题翻译过来,和我前面遇到的问题一模一样:
为什么用 Float 或者 Double 除以零不会抛出 java.lang.ArithmeticExceptionL:/by zero 异常?
这个问题下的高赞回答是这样的:
问题的终极答案就藏在这个高赞回答中,我给你解析一番。
揭秘
这个高赞回答,其实就只有一句话,其他的部分都是引用:
In short, that's the way it's specified in the IEEE-754 standard, which is what Java's Floating-Point Operations are based on.
在这一句话中,他提到了两个关键的东西:
-
IEEE-754 standard -
Java's Floating-Point Operations
意思就是 Java 的浮点运算是基于 IEEE-754 标准来的。
他给的其中一个超链接是 Java 语言规范:
https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3
Java 语言规范表示:你要问我为什么,我只能告诉你我遵守的是 IEEE 754 这个国际规范。
所以,别问:
那么这个 IEEE 754 是个什么东西呢?
我也不知道,所以查一下:
好家伙,来头还不小。
IEEE,全称 Institute of Electrical and Electronics Engineers,电气和电子工程师协会。
IEEE 754 的全称是 IEEE Standard for Floating-Point Arithmetic。表示电气和电子工程师协会制定的浮点运算技术标准。
Standard,标准,你明白吧?
得有一些 Standard,有些事情才好办,不然各自为战,各自兼容,难受的一比。
所以,该标准是为了解决在不同的浮点实现中的各种问题,这些问题使它们难以可靠地使用和移植。
一旦有了标准,大家都遵守,就好办了。
在标准中就规定了对于异常应该如何处理:
来,框起来的部分,跟我大声地朗读一遍:
Division by zero: an operation on finite operands gives an exact infinite result, e.g., 1/0 or log(0). By default, returns &plu**n;infinity.
针对“除以 0”异常,IEEE 754 规定:对有限操作数的运算会得到一个精确的无限结果,例如,1/0 或 log(0)。默认情况下,返回 &plu**n;infinity。
规定就是标准,标准就是规定。遵守就完事了。
如果你非要问:为什么标准中要这样的规定呢?
在前面提到的高赞回答中,给到了这样的一个链接:
https://web.archive.org/web/20180112211305/http://grouper.ieee.org/groups/754/faq.html#exceptions
这个问题的答案就藏在这个链接里面:
请问:为什么除以零(或溢出,或下溢)不会停止程序或引发错误?
下面给了一大段回复,我尝试着理解了几次,但是我发现有点超纲了,确实不知道具体啥意思。
我个人浅显的认为它要表达的意思是:这玩意使用范围很广,为了程序的稳定性,我不想抛出异常来终止程序,而使用者应该知道我这个“除 0 之后是一个无穷大的数”这样的设定。
如果你非要问:到底为什么要这样设定呢?
好了,
别问了,
就到这吧。
再问,
就不礼貌了。
看完之后,你只需要记住一句话:在 Java 里面,除数作为 0,不一定会抛出 ArithmeticException,千万不要形成这样的固化思维,从而影响自己排查问题的方向。
下面这个环节叫做[荒腔走板],技术文章后面我偶尔会记录、分享点生活相关的事情,和技术毫无关系。我知道看起来很突兀,但是我喜欢,因为这是一个普通博主的生活气息。
你要不喜欢,退出之前记得文末点个“在看”哦。
荒腔走板
推荐一个动漫,我最近刚刚在 B 站刷完。
我刷这个动漫完全是因为有一天晚上夜跑的时候,路过一个十字路口,一阵极具夏天味道的、又强又热的横风从我的侧面吹过来。
我戴着降噪耳机,听不到自己的心跳,也听不到自己的脚步声,反而是风声,听的清清楚楚。
那一瞬间,我想起了这部改编自同名书的动漫:《强风吹拂》。
如果你可能对这个动漫无感。但是对于我而言,它确实有一股神奇的力量。不论是跑的轻松或者跑的痛苦的时候,都能激励到我。特别是有时候不是那么想跑,或者跑的比较难受,给自己做心理建设的时,我都会想到这部动漫,想到最后几集,他们站在赛道上之后的内心独白。
跑步是什么?
我也不知道,但是我知道它不是简单的两**替前进,只有跑起来才能感受到它。感受来自身体和心理的痛苦,以及跑完既定目标之后的喜悦。
在书中,有一句话是这样写的:明明这么痛苦,这么难过,为什么就是不能放弃跑步?因为全身细胞都在蠢蠢欲动,想要感受强风迎面吹拂的滋味。
是的,是风声,是贴耳拂过的风声。当我在专注的感受风声的时候,就是跑步中最快乐的时候。
终有疾风起,人生不言弃。
推荐给你。
你好呀,我是歪歪。我没进过一线大厂,没创过业,也没写过书,更不是技术专家,所以也没有什么亮眼的title。
当年高考,随缘调剂到了某二本院校计算机专业。纯属误打误撞,进入程序员的行列,之后开始了运气爆棚的程序员之路。
说起程序员之路还是有点意思,可以点击蓝字,查看我的程序员之路。