編寫高質量代碼:改善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個建議@目錄

相關文章
相關標籤/搜索