编写高质量代码:改善Java程序的151个建议(第2章:基本类型___建议21~30)

不积跬步,无以致千里;不积小流,无以成江海。 --荀子《劝学篇》java

建议21:用偶判断,不用奇判断算法

建议22:用证书类型处理货币数据库

建议23:不要让类型默默转换安全

建议24:边界仍是边界dom

建议25:不要让四舍五入亏了一方函数

建议26:提防包装类型的null值性能

建议27:谨慎包装类型额大小比较单元测试

建议28:优先使用整形池测试

建议29:优先选择基本类型网站

建议30:不要随便设置随机种子

建议21:用偶判断,不用奇判断

判断一个数是奇数仍是偶数是小学里的基本知识,可以被2整除的整数是偶数,不能被2整除的数是奇数,这规则简单明了,还有什么可考虑的?好,咱们来看一个例子,代码以下:

import java.util.Scanner;

public class Client21 {
    public static void main(String[] args) {
        // 接收键盘输入参数
        Scanner input = new Scanner(System.in);
        System.out.println("输入多个数字判断奇偶:");
        while (input.hasNextInt()) {
            int i = input.nextInt();
            String str = i + "-->" + (i % 2 == 1 ? "奇数" : "偶数");
            System.out.println(str);

        }
    }
}

输入多个数字,而后判断每一个数字的奇偶性,不能被2整除的就是奇数,其它的都是偶数,彻底是根据奇偶数的定义编写的程序,咱们开看看打印的结果:

  输入多个数字判断奇偶:1  2  0  -1 -2     1-->奇数    2-->偶数    0-->偶数     -1-->偶数       -2-->偶数

前三个还很靠谱,第四个参数-1怎么多是偶数呢,这Java也太差劲了吧。

看到这段程序,你们都会心的笑了,原来Java这么处理取余计算的呀,根据上面的模拟取余可知,当输入-1的时候,运算结果为-1,固然不等于1了,因此它就被断定为偶数了,也就是咱们的判断失误了。问题明白了,修正也很简单,改成判断是不是偶数便可。代码以下:     i % 2 == 0 ? "偶数" : "奇数";

注意:对于基础知识,咱们应该"知其然,并知其因此然"。

建议22:用证书类型处理货币

在平常生活中,最容易接触的小数就是货币,好比,你付给售货员10元钱购买一个9.6元的零食,售货员应该找你0.4元,也就是4毛钱才对,咱们来看下面的程序:

public class Client22 {
    public static void main(String[] args) {
        System.out.println(10.00-9.60);
    }
}

咱们的指望结果是0.4,也应该是这个数字,可是打印出来的倒是:0.40000000000000036,这是为何呢?

这是由于在计算机中浮点数有可能(注意是有可能)是不许确的,它只能无限接近准确值,而不能彻底精确。为何会如此呢?这是由浮点数的存储规则所决定的,咱们先来看看0.4这个十进制小数如何转换成二进制小数,使用"乘2取整,顺序排列"法,咱们发现0.4不能使用二进制准确的表示,在二进制数世界里它是一个无限循环的小数,就像在十进制的世界里没有办法惟一准确表示1/3。

public class Client22 {
    public static void main(String[] args) {
        NumberFormat f = new DecimalFormat("#.##");
        System.out.println(f.format(10.00-9.60));
    }
}

打印出的结果是0.4,看似解决了。可是隐藏了一个很深的问题。咱们来思考一下金融行业的计算方法,会计系统通常记录小数点后的4为小数,可是在汇总、展示、报表中、则只记录小数点后的2位小数,若是使用浮点数来计算货币,想一想看,在大批量加减乘除后结果会有很大的差距(其中还涉及到四舍五入的问题)!会计系统要求的就是准确,可是由于计算机的缘故不许确了,那真是罪过,要解决此问题有两种方法:

一、使用BigDecimal

BigDecimal是专门为弥补浮点数没法精确计算的缺憾而设计的类,而且它自己也提供了加减乘除的经常使用数学算法。特别是与数据库Decimal类型的字段映射时,BigDecimal是最优的解决方案。

代码实例

声明BigDecimal对象的时候必定要使用它构造参数为String的类型的构造器。

二、使用整型

把参与运算的值扩大100倍,并转为整型,而后在展示时再缩小100倍,这样处理的好处是计算简单,准确,通常在非金融行业(如零售行业)应用较多。此方法还会用于某些零售POS机,他们输入和输出的所有是整数,那运算就更简单了.

注:乘2取整,顺序排列

十进制小数转换成二进制小数采用"乘2取整,顺序排列"法。具体作法是:用2乘十进制小数,能够获得积,将积的整数部分取出,再用2乘余下的小数部分,又获得一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,此时0或1为二进制的最后一位。或者达到所要求的精度为止。
 

0.96875
X 2
1.9375 取1后变成 0.9375 (如下省略不写了)
X 2
1.875 取1
X 2
1.75 取1
X 2
1.5 取1
X 2
1.0 取1后变成 0,结束转换

0.96875=(0.11111)2

 

建议23:不要让类型默默转换

咱们作一个小学生的题目,光速每秒30万千米,根据光线的旅行时间,计算月球和地球,太阳和地球之间的距离。代码以下: 

public class Client23 {
    // 光速是30万千米/秒,常量
    public static final int LIGHT_SPEED = 30 * 10000 * 1000;

    public static void main(String[] args) {
        System.out.println("题目1:月球照射到地球须要一秒,计算月亮和地球的距离。");
        long dis1 = LIGHT_SPEED * 1;
        System.out.println("月球与地球的距离是:" + dis1 + " 米 ");
        System.out.println("-------------------------------");
        System.out.println("题目2:太阳光照射到地球须要8分钟,计算太阳到地球的距离.");
        // 可能要超出整数范围,使用long型
        long dis2 = LIGHT_SPEED * 60 * 8;
        System.out.println("太阳与地球之间的距离是:" + dis2 + " 米");
    }
}

 

Java是先运算而后再进行类型转换的,具体的说dis2的三个运算参数都是int型,三者相乘结果也是int型,可是超出了int的最大值,就变成负值了,越界了从新开始。

而dis3中int60变为了long60L,长整型,(Java基本转换规则,向数据范围大的方向转换,也叫加宽类型),在尚未超出int型范围的时候就已经转化成long型了,解决了越界问题,实际开发中,更通用的作法是主动声明类型转化,而不是强制类型转换,

long dis2 = 1L * LIGHT_SPEED * 60L * 8

既然指望的结果是long型,那就让第一个参与的参数也是Long(1L)吧,也就说明"嗨"我已是长整型了,大家都跟着我一块转为长整型吧。

注意:基本类型转换时,使用主动声明方式减小没必要要的Bug。

建议24:边界仍是边界

某商家生产的电子产品很是畅销,须要提早30天预订才能抢到手,同时还规定了一个会员可拥有的最多产品数量,目的是为了防止囤积压货肆意加价。会员的预订过程是这样的:先登陆官方网站,选择产品型号,而后设置须要预订的数量,提交,符合规则即提示下单成功,不符合规则提示下单失败,后台的处理模拟以下:

public class DynamicCompileDemo {
        // 一个会员拥有产品的最多数量
        public final static int LIMIT = 2000;
        public static void main(String[] args) {
            // 会员当前用有的产品数量
            int cur = 1000;
            Scanner input = new Scanner(System.in);
            System.out.println("请输入须要预约的数量:");
            while (input.hasNextInt()) {
                int order = input.nextInt();
                if (order > 0 && order + cur <= LIMIT) {
                    cur = cur + order;
                    System.out.println("你已经成功预约:" + cur  + " 个产品");
                } else {
                    System.out.println("超过限额,预约失败!");
                }
            }
        }
    }

居然预约了-2147481829 个产品,真的是奇葩啊。

看着2147483647这个数字很眼熟?那就对了,这个数字就是int类型的最大值,没错,有人输入了一个最大值,使校验条件失败了,Why?咱们来看程序,order的值是2147483647那再加上1000就超出int的范围了,其结果是-2147482649,那固然是小于正数2000了!一句归其缘由:数字越界使校验条件失效。

在单元测试中,有一项测试叫作边界测试(也叫临界测试),若是一个方法接收的是int类型的参数,那么如下三个值是必须测试的:0、正最大、负最小,其中正最大、负最小是边界值,若是这三个值都没有问题,方法才是比较安全可靠的。咱们的例子就是由于缺乏边界测试,导致生产系统产生了严重的误差。

建议25:不要让四舍五入亏了一方

System.out.println("10.5近似值: "+Math.round(10.5));
System.out.println("-10.5近似值: "+Math.round(-10.5));

输出结果为:10.5近似值: 11       -10.5近似值: -10

银行家舍入(Banker's Round)的近似算法:

四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

咱们举例说明,取2位精度;

round(10.5551)  =  10.56   round(10.555)  =  10.56   round(10.545)  =  10.54 

注意:根据不一样的场景,慎重选择不一样的舍入模式,以提升项目的精准度,减小算法损失。

建议26:提防包装类型的null值

包装类型参与运算时,要作null值校验。

建议27:谨慎包装类型额大小比较

建议28:优先使用整形池

一、valueOf()返回的是原对象

二、valueOf()方法返回的是如今到1970年1月1日00:00:00的数值类型的毫秒数

三、包装对象的valueOf()方法返回该包装对象对应的原始值

四、装箱动做是经过valueOf方法实现的

经过valueOf产生包装对象时,若是int参数在-128到127之间,直接从整型池中获取对象,不在范围内的int类型则经过new生成包装类型。

127的包装对象直接从整型池中得到,而12八、555超出了整型池范围,是经过new产生的一个新对象,地址不一样,==对比就不一样了。

整型池的存在提升了系统性能,节约了内存空间,也就是在生成包装对象的时候使用valueOf生成,而不是经过构造函数来生成的缘由。

顺便说一下,在判断对象释放相等的时候,最好使用equals方法,避免使用==产生非预期的效果。

这个的实际意思是否是就是:

使用Integer.valueOf(1)比使用Integer i = new Interger(1);

系统性能好,更节约内存空间。

建议29:优先选择基本类型

建议30:不要随便设置随机种子

一、什么是随机种子?

随机种子是基于随机数的计算机专业术语,随机数是以随机种子做为初始条件,而后经过必定的算法不停迭代产生的。

在Java中,随机数的产生取决于种子,随机数与种子之间的关系:

① 种子不一样,产生不一样的随机数

② 种子相同,即便实例不一样也会产生相同的随机数。

二、设置随机种子的两种方法:

若设置随机种子则相同的种子,产生的随机数相同。若不设置则每次随机的不一样。

Random rnd = new Random();

rnd.setSeed()用于设置种子。

rnd.nextInt() 用于产生随机数。

rnd.nextInt(10); // 0-10之间。
Random r = new Random(1000);//1000就是一个随机种子
for(int i=1; i<=4; i++){
    System.out.println("第"+i+"次:"+r.nextInt());   
}

三、Java中获取随机数的两种方式

java.util.Random类得到随机数和Math.random()。

 

编写高质量代码:改善Java程序的151个建议@目录

相关文章
相关标签/搜索