JobPlus知识库 IT 软件开发 文章
Java陷阱(一)

摘自《Java解惑》。这些问题都很经典,可以细细品味。
今天讲解的问题如下,奇数性问题、长整除问题、找零时刻、多重转型、Dos Equis。

奇数性

1.       public class Odd { 

2.           public static void main(String[] args) { 

3.               System.out.println("1是奇数吗?"+isOdd(1)); 

4.               System.out.println("2是奇数吗?"+isOdd(2)); 

5.               System.out.println("-1是奇数吗?"+isOdd(-1)); 

6.           } 

7.           public static boolean isOdd(int i){ 

8.               return i % 2 == 1; 

9.           } 

10.    }

分析

这是Java对取余操作符(%)的定义所产生的。isOdd方法对于对所有负奇数的判断都会失败。在任何负整数上调用该方法都回返回false,不管该整数是偶数还是奇数。

建议

无论你何时使用到了取余操作符,都要考虑到操作数和结果的符号。

解决

方案一:

1.       public static boolean isOdd(int i){ 

2.         return i % 2 != 0; 

3.       }

方案二:

1.       public static boolean isOdd2(int i){ 

2.         return (i & 1) != 0; 

3.       } 

长整除

1.       public class LongDivision { 

2.         publicstatic void main(String[] args) { 

3.             final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000; 

4.             final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000; 

5.             System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY); 

6.         } 

7.       } 

分析

当两个int数值相乘时,将得到另一个int数值。因此最后的结果是int数值,从而导致溢出。

建议

当在操作很大的数字时,千万要提防溢出。

解决

方案:强制表达式中的所有后续计算都用long运算来完成

1.       public class LongDivision2 { 

2.         public static void main(String[] args) { 

3.             final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000; 

4.             final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000; 

5.             System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY); 

6.         }  

7.       } 

找零时刻

1.       public class Change { 

2.         public static void main(String[] args) { 

3.             System.out.println(2.0-1.1); 

4.         } 

5.       }

分析

并不是所有的小数都可以用二进制浮点数精确表示。

建议

在需要精确答案的地方,要避免使用float和double。对于货币计算,要使用int、long、BigDecimal。一定要用BigDecimal(String)构造器,而千万不要用BigDecimal(double)。后一个构造器将用它的参数的精确值来创建一个实例。

解决

方案一:JDK5.0或更新版本,可以使用printf方法

1.       public class Change2 { 

2.         public static void main(String[] args) { 

3.             System.out.printf("%.2f",2.0-1.1); 

4.         } 

5.       }

方案二:使用BigDecimal类

1.       public class Change3 { 

2.         public static void main(String[] args) { 

3.             BigDecimal bigNum1 = newBigDecimal("2.0"); 

4.             BigDecimal bigNum2 = newBigDecimal("1.1"); 

5.             System.out.println(bigNum1.subtract(bigNum2)); 

6.         } 

7.       } 

初级问题

1.       public class Elementary { 

2.         public static void main(String[] args) { 

3.             System.out.println(12345+5432l); 

4.         } 

5.       }

分析

“5432l”中的“l”是小写的“L”。

建议

在long类型常量中,一定要用大写的L,千万不要使用小写的l。类似地,要避免使用单个l字母作为变量名。

解决

方案:

1.       public class Elementary { 

2.         public static void main(String[] args) { 

3.             System.out.println(12345+5432L); 

4.         } 

5.       }  

多重转型

1.       public class Multicast { 

2.         public static void main(String[] args) { 

3.             System.out.println((int)(char)(byte)-1); 

4.         } 

5.       }

分析

如果最初的数值类型是有符号的,就执行符号扩展。如果是char,那么不管它将要被转换成什么类型,都执行零扩展。

Dos Equis

1.       public class DosEquis { 

2.         public static void main(String[] args) { 

3.             char x = 'X'; 

4.             int i = 0; 

5.             System.out.println(true?x:0); 

6.             System.out.println(false?i:x); 

7.         } 

8.       }

分析

如果第2个和第3个操作数具有相同的类型,那么它就是条件表达式的类型。如果一个操作数的类型是T,T表示byte、short、char,而另一个操作数是一个int类型的常量表达式,它的值可以用类型T表示。否则,将对操作数类型进行二进制数字提升,而条件表达式的类型就是第2个和第3个操作数被提升之后的类型。

建议

最好在表达式中使用类型相同的第2个和第3个操作数。

 


如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

¥ 打赏支持
315人赞 举报
分享到
用户评价(0)

暂无评价,你也可以发布评价哦:)

扫码APP

扫描使用APP

扫码使用

扫描使用小程序