读改善java程序的151个建议(3)

21.用偶判断,不用奇判断
在判断奇偶的情况下,用偶来判断,例:i%2==0?"偶":"奇"
取余基础知识(模拟代码如下):
public static int remainder(int dividend,int divisor){
return dividend-dividend/divisor*divisor;
}

22.用整数类型处理贷币
public  static  void  main ( String []  args ) {

                // TODO Auto-generated method stub
                System .out. println  (10.00-9.60);
       }
我们期望的结果是0.4,但打印出来的却是0.40000000000000036
这是因为在计算机中浮点数有可能(注意是可能)是不准确的,它只能无限接近准确值,而不能完全精确。
在程序中,虽然我们可以通过对结果取整来或格式化来处理,如:
               NumberFormat  format= new  DecimalFormat  ( "#.##"  );
                System .out. println  (format. format  (10.00-9.60));
但在大批量的加减乘除后结果会有很大的差距。
要解决此问题,有两种方法:
(1)使用BigDecimal:专门为弥补浮点数无法精确认算的缺憾而设计的类,特别是与数据库Decimal类型的字段映身时,BigDecimal是最优的解决方案
(2)使用整型:把参与运算的值扩大100倍,并转变为整型 ,然后在展现时再缩小100倍

23.不要让类型默认转换
此处讲的主要针对一些基本类型之间的转换,需要注意的一点是在java中是先运算然后再进行类型转换的。
例如:public static finat int LIGHT_SPEED=30*1000*1000;
在计算 long dis2=LIGHT_SPEED*60*8; 的时候,计算出来的dis2将会是一个负值。这是因为dis2的三个运算参数都是int类型,三者相乘的结果自然也是int类型,但是已经超过int的最大值(2147483647),越界了,变成了负值,再转换为long型时,结果还是负值。
问题知道了,解决起来也很简单,只要加个小小的“L”即可,long dis2=LIGHT_SPEED*60L*8;在实际开发中,更通用的做法是主动声明式类型转化:long dis2=1L*LIGHT_SPEED*60*8;
总之,基本类型转换时,使用主动声明方式减少不必要的bug

24.边界、边界,还是办界
主要是在一些数值的测试中要考虑到边界值可能出现的情况

25.不要让四舍五入亏了一方
主要说的是银行家舍入法则:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。
编码中可使用RoundingMode类提供的Round模式即可。如此处的银行家舍入法则对应的模式为RoundingMode.HALF_EVEN;

26.提防包装类型的null值
谨记一点:包装类型参与运算时,要做null校验

27.谨慎包装类型 的大小比较
在java中,“==”是用来判断两个操作数是否有相等关系的,如果是基本类型则判断值是否相等,如果是对象则判断是否是一个对象的两个引用,也就是地址是否相等。
引申:
java中的数据类型,可分为两类: 
(1).基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 
  他们之间的比较,应用双等号(==),比较的是他们的值。 
(2).复合数据类型(类) 
  当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
  对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。

28.优先使用整型池
整型池,在整型的装箱动作valueOf方法中,IntegerCache.cache[i+offset];  这里的cache是IntegerCache内部类的一个静态数组,容纳的是-128到127之间的Integer对象。能过valueOf产生包装对象时,如果int参数在-128至127之间,则直接从整型池中获得对象,不在该范围的int类型 则通过new生成包装对象。
总结:通过包装类型的valueOf生成包装实例可以显著提高空间和时间性能。

29.优先选择基本类型
自动装箱有一个重要的原则:基本类型可以先加宽,再转变为宽类型的包装类型,但不能直接转变成宽类型的包装类型。
以下程序编译是通不过的:

         public   static  void   main (  String []  args ) {

                int  i =100;
               f(i);
       }
       
         public   static  void   f (  Long   l ){
              
       }

30.不要随便设置随机种子
java.util.Random的有参构造,运行结果,计算机不同输出的随机数不同,但是有一点是相同的:在同一台机器上,甭管运行多少次,所打印的随机数都是相同的,也就是说第一次运行,会打印出三个随机数,第二次运行还是打印出这三个随机数,只要在同一台硬件机器上,就永远都会打印出相同的随机数,问题在哪?
                //test1
                Random  random= new  Random  ();
                for  ( int  j=1;j<4;j++){
                       System  .out. println  ( "第"  +j+ "次:"  +random. nextInt  ());
              }
                //test2 在同一台机器上,不管运行多少次,打印出相同的随机数
                Random  r= new  Random  (1000);
                for  ( int  j=1;j<4;j++){
                       System  .out. println  ( "第"  +j+ "次:"  +r. nextInt  ());
              }
                //test3 打印出不相同的随机数
                Random  random2=  new   Random  ();
                for  ( int  j=1;j<4;j++){
                       System  .out. println  ( "第"  +j+ "次:"  +random2. nextInt  (1001));
              }

那是因为产生随机数的种子被固定了,在java中,随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:1)种子不同,产生不同的随机数 2)种子相同,即使实例不同也产生相同的随机数。
参看Random的源码,Random类的默认种子(无参构造)是System.nanoTime()的返回值。这个值是距离某一个固定时间点的纳秒数,不同的操作系统和硬件有不同的固定时间点,也就是说不同的操作系统其纳称值是不同的,而同一个操作系统纳秒值也会不同,随机数自然也就不同了。(顺便说下,System.nanoTime不能用于计算日期,那是因为固定的时间点是不确定的,纳秒值可能是负值,这与System.currentTimeMills不同。
而new Random(1000),显示设置了随机种子为1000,运行多次,虽然实例不同,但都会获得相同的三个随机数。另:Math.Random()原理与其相同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值