Java開發手冊-(轉自阿里雲棲社區)

Java開發手冊下載鏈接

1-0.9=0.1是天經地義的,但在計算機的世界裏,0.1恰恰是無法精確表示的一個小數,只有2的冪次倍小數才能夠精確表示,如:0.5、0.25、0.125等。由於0.1是近似表達,在各種情形中的計算存在數位的取捨精度不一樣,所以1-0.9未必等於0.9-0.8,所以浮點數之間的等值判斷,基本數據類型不能用==來比較,包裝數據類型不能用equals來判斷。包裝類型運算也是調用的浮點類型的計算

public class FloatPrimitiveTest {
    public static void main(String[] args) {
        float a = 1.0f - 0.9f;
        float b = 0.9f - 0.8f;
        if (a == b) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }
    }
}
輸出------------false


public class FloatWrapperTest {
    public static void main(String[] args) {
        Float a = Float.valueOf(1.0f - 0.9f);
        Float b = Float.valueOf(0.9f - 0.8f);
        if (a.equals(b)) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }
    }
}
輸出--------false
正例--------------------------------
(1) 指定一個誤差範圍,兩個浮點數的差值在此範圍之內,則認爲是相等的。
 float a = 1.0f - 0.9f;
 float b = 0.9f - 0.8f;
 float diff = 1e-6f;
 if (Math.abs(a - b) < diff) {
     System.out.println("true");
 }
(2) 使用 BigDecimal 來定義值,再進行浮點數的運算操作。
 BigDecimal a = new BigDecimal("1.0");
 BigDecimal b = new BigDecimal("0.9");
 BigDecimal c = new BigDecimal("0.8");
 BigDecimal x = a.subtract(b);
 BigDecimal y = b.subtract(c);
 if (x.equals(y)) {
     System.out.println("true");
 }

當 switch 括號內的變量類型爲 String 並且此變量爲外部參數時,必須先進行 null判斷。

public class SwitchTest {
    public static void main(String[] args) {
        String param = null;
        switch (param) {
            case "null":
                System.out.println("null");
                break;
            default:
                System.out.println("default");
        }
    }
}
拋出NPE異常

爲了防止精度損失,禁止使用構造方法 BigDecimal(double)的方式把 double 值轉化爲 BigDecimal 對象。
BigDecimal(double)存在精度損失風險,在精確計算或值比較的場景中可能會導致業務邏輯異常。
如:BigDecimal g = new BigDecimal(0.1f); 實際的存儲值爲:0.10000000149
優先推薦入參爲 String 的構造方法,或使用 BigDecimal 的 valueOf 方法,此方法內部其實執行了Double 的 toString,而 Double 的 toString 按 double 的實際能表達的精度對尾數進行了截斷

推薦使用的方式
BigDecimal recommend1 = new BigDecimal("0.1");
BigDecimal recommend2 = BigDecimal.valueOf(0.1);

在使用阻塞等待獲取鎖的方式中,必須在 try 代碼塊之外,並且在加鎖方法與 try 代碼塊之間沒有任何可能拋出異常的方法調用,避免加鎖成功後,在 finally 中無法解鎖。
如果 lock 方法在 try 代碼塊之內,可能由於其它方法拋出異常,導致在 finally代碼塊中,unlock 對未加鎖的對象解鎖,它會調用 AQS 的 tryRelease 方法(取決於具體實現類),拋出 IllegalMonitorStateException 異常。在 Lock 對象的 lock方法實現中可能拋出 unchecked 異常。而在使用嘗試機制來獲取鎖的方式中,比如 tryLock(),在進入業務代碼塊之前,必須先判斷當前線程是否持有鎖。

public class LockTest {
    private final static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        try {
            lock.tryLock();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
所以這個unlock不會拋出異常
正確加鎖寫法
Lock lock = new XxxLock();
        // ...
    lock.lock();
    try {
         doSomething();
         doOthers();
    } finally {
         lock.unlock();
   }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章