Java陷阱(一)
欢迎来到阿八个人博客网站。本 阿八个人博客 网站提供最新的站长新闻,各种互联网资讯。 喜欢本站的朋友可以收藏本站,或者加QQ:我们大家一起来交流技术! URL链接:https://www.abboke.com/xwzhj/2019/0611/376.html
文章目录
摘自《Java解惑》。这些问题都很经典,可以细细品味。
今天讲解的问题如下,奇数性问题、长整除问题、找零时刻、多重转型、Dos Equis。
奇数性
public class Odd { public static void main(String[] args) { System.out.println("1是奇数吗?"+isOdd(1)); System.out.println("2是奇数吗?"+isOdd(2)); System.out.println("-1是奇数吗?"+isOdd(-1)); } public static boolean isOdd(int i){ return i % 2 == 1; } }
分析
这是Java对取余操作符(%)的定义所产生的。isOdd方法对于对所有负奇数的判断都会失败。在任何负整数上调用该方法都回返回false,不管该整数是偶数还是奇数。
建议
无论你何时使用到了取余操作符,都要考虑到操作数和结果的符号。
解决
方案一:
public static boolean isOdd(int i){ return i % 2 != 0; }方案二:
public static boolean isOdd2(int i){ return (i & 1) != 0; }
长整除
public class LongDivision { publicstatic void main(String[] args) { final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000; final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000; System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY); } }
分析
当两个int数值相乘时,将得到另一个int数值。因此最后的结果是int数值,从而导致溢出。
建议
当在操作很大的数字时,千万要提防溢出。
解决
方案:强制表达式中的所有后续计算都用long运算来完成
public class LongDivision2 { public static void main(String[] args) { final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000; final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000; System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY); } }
找零时刻
public class Change { public static void main(String[] args) { System.out.println(2.0-1.1); } }
分析
并不是所有的小数都可以用二进制浮点数精确表示。
建议
在需要精确答案的地方,要避免使用float和double。对于货币计算,要使用int、long、BigDecimal。一定要用BigDecimal(String)构造器,而千万不要用BigDecimal(double)。后一个构造器将用它的参数的精确值来创建一个实例。
解决
方案一:JDK5.0或更新版本,可以使用printf方法
public class Change2 { public static void main(String[] args) { System.out.printf("%.2f",2.0-1.1); } }方案二:使用BigDecimal类
public class Change3 { public static void main(String[] args) { BigDecimal bigNum1 = newBigDecimal("2.0"); BigDecimal bigNum2 = newBigDecimal("1.1"); System.out.println(bigNum1.subtract(bigNum2)); } }
初级问题
public class Elementary { public static void main(String[] args) { System.out.println(12345+5432l); } }
分析
“5432l”中的“l”是小写的“L”。
建议
在long类型常量中,一定要用大写的L,千万不要使用小写的l。类似地,要避免使用单个l字母作为变量名。
解决
方案:
public class Elementary { public static void main(String[] args) { System.out.println(12345+5432L); } }
多重转型
public class Multicast { public static void main(String[] args) { System.out.println((int)(char)(byte)-1); } }
分析
如果最初的数值类型是有符号的,就执行符号扩展。如果是char,那么不管它将要被转换成什么类型,都执行零扩展。
Dos Equis
public class DosEquis { public static void main(String[] args) { char x = 'X'; int i = 0; System.out.println(true?x:0); System.out.println(false?i:x); } }
分析
如果第2个和第3个操作数具有相同的类型,那么它就是条件表达式的类型。如果一个操作数的类型是T,T表示byte、short、char,而另一个操作数是一个int类型的常量表达式,它的值可以用类型T表示。否则,将对操作数类型进行二进制数字提升,而条件表达式的类型就是第2个和第3个操作数被提升之后的类型。
建议
最好在表达式中使用类型相同的第2个和第3个操作数。