中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java中的Number怎么使用

發布時間:2021-11-24 16:20:49 來源:億速云 閱讀:192 作者:iii 欄目:大數據

本篇內容主要講解“java中的Number怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“java中的Number怎么使用”吧!

簡介

java中可以被稱為Number的有byte,short,int,long,float,double和char,我們在使用這些Nubmer的過程中,需要注意些什么內容呢?一起來看看吧。

Number的范圍

每種Number類型都有它的范圍,我們看下java中Number類型的范圍:

java中的Number怎么使用

考慮到我們最常用的int操作,雖然int的范圍夠大,但是如果我們在做一些int操作的時候還是可能超出int的范圍。

超出了int范圍會發送什么事情呢?看下面的例子:

    public void testIntegerOverflow(){
        System.out.println(Integer.MAX_VALUE+1000);
    }

運行結果:-2147482649。

很明顯Integer.MAX_VALUE+1000將會超出Integer的最大值范圍,但是我們沒有得到異常提醒,反而得到了一個錯誤的結果。

正確的操作是如果我們遇到了Overflow的問題,需要拋出異常:ArithmeticException。

怎么防止這種IntegerOverflow的問題呢?一般來講,我們有下面幾種方式。

  • 第一種方式:在做Integer操作之前,進行預判斷是否超出范圍:

舉個例子:

    static final int safeAdd(int left, int right) {
        if (right > 0 ? left > Integer.MAX_VALUE - right
                : left < Integer.MIN_VALUE - right) {
            throw new ArithmeticException("Integer overflow");
        }
        return left + right;
    }

上面的例子中,我們需要進行兩個整數相加操作,在相加之前,我們需要進行范圍的判斷,從而保證計算的安全性。

  • 第二種方式:使用Math的addExact和multiplyExact方法:

Math的addExact和multiplyExact方法已經提供了Overflow的判斷,我們看下addExact的實現:

    public static int addExact(int x, int y) {
        int r = x + y;
        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
        if (((x ^ r) & (y ^ r)) < 0) {
            throw new ArithmeticException("integer overflow");
        }
        return r;
    }

看下怎么使用:

    public int addUseMath(int a, int b){
        return Math.addExact(a,b);
    }
  • 第三種方式:向上轉型

既然超出了Integer的范圍,那么我們可以用范圍更大的long來存儲數據。

    public static long intRangeCheck(long value) {
        if ((value < Integer.MIN_VALUE) || (value > Integer.MAX_VALUE)) {
            throw new ArithmeticException("Integer overflow");
        }
        return value;
    }

    public int addUseUpcasting(int a, int b){
        return (int)intRangeCheck((long)a+(long)b);
    }

上面的例子中,我們將a+b轉換成了兩個long相加,從而保證不溢出范圍。

然后進行一次范圍比較,從而判斷相加之后的結果是否仍然在整數范圍內。

  • 第四種方式:使用BigInteger

我們可以使用BigInteger.valueOf(a)將int轉換成為BigInteger,再進行后續操作:

    public int useBigInteger(int a, int b){
        return BigInteger.valueOf(a).add(BigInteger.valueOf(b)).intValue();
    }

區分位運算和算數運算

我們通常會對Integer進行位運算或者算數運算。雖然可以進行兩種運算,但是最好不要將兩種運算同時進行,這樣會造成混淆。

比如下面的例子:

x += (x << 1) + 1;

上面的例子是想做什么呢?其實它是想將3x+1的值賦給x。

但是這樣寫出來讓人很難理解,所以我們需要避免這樣實現。

再看下面的一個例子:

    public void testBitwiseOperation(){
        int i = -10;
        System.out.println(i>>>2);
        System.out.println(i>>2);
        System.out.println(i/4);
    }

本來我們想做的是將i除以4,結果發現只有最后一個才是我們要的結果。

我們來解釋一下,第一個i>>>2是邏輯右移,將會把最左邊的填充成0,所以得出的結果是一個正值1073741821。

第二個i>>2是算數右移,最左邊的還是會填充成1,但是會向下取整,所以得出結果是-3.

直接使用i/4,我們是向上取整,所以得出結果是-2.

注意不要使用0作為除數

我們在使用變量作為除數的時候,一定要注意先判斷是否為0.

兼容C++的無符號整數類型

在java中只有16位的char表示的是無符號整數,而int實際上表示的是帶符號的整數。

而在C或者C++中是可以直接表示無符號的整數的,那么,如果我們有一個32位的無符號整數,該怎么用java來處理呢?

    public int readIntWrong(DataInputStream is) throws IOException {
        return is.readInt();
    }

看上面的例子,我們從Stream中讀取一個int值,如果是一個32位的無符號整數,那么讀出來int就變成了有符號的負整數,這和我們的期望是相符的。

考慮一下,long是64位的,我們是不是可以使用long來表示32位的無符號整數呢?

    public long readIntRight(DataInputStream is) throws IOException{
        return is.readInt() & 0xFFFFFFFFL; // Mask with 32 one-bits
    }

看上面的例子,我們返回的是long,如果將32位的int轉換成為64位的long,會自動根據符號位進行補全。

所以這時候我們需要和0xFFFFFFFFL進行mask操作,將高32位重置為0.

NAN和INFINITY

在整型運算中,除數是不能為0的,否則直接運行異常。但是在浮點數運算中,引入了NAN和INFINITY的概念,我們來看一下Double和Float中的定義。

public static final double POSITIVE_INFINITY = 1.0 / 0.0;
public static final double NEGATIVE_INFINITY = -1.0 / 0.0;
public static final double NaN = 0.0d / 0.0;
public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
public static final float NaN = 0.0f / 0.0f;

1除以0就是INFINITY,而0除以0就是NaN。

接下來,我們看一下NAN和INFINITY的比較:

public void compareInfinity(){
    System.out.println(Double.POSITIVE_INFINITY == Double.POSITIVE_INFINITY);
    }

運行結果是true。

    public void compareNaN(){
        System.out.println(Double.NaN == Double.NaN);
    }

運行結果是false。

可以看到NaN和NaN相比是false。

那么我們怎么比較NaN呢?

別急,Double提供了一個isNaN方法,我們可以這樣使用:

System.out.println(Double.isNaN(Double.NaN));

接下來我們看一個在代碼中經常會用到的一個Double解析:

    public void incorrectParse(String userInput){
        double val = 0;
        try {
            val = Double.valueOf(userInput);
        } catch (NumberFormatException e) {
        }
        //do something for val
    }

這段代碼有沒有問題?咋看下好像沒有問題,但是,如果我們的userInput是NaN,Infinity,或者-Infinity,Double.valueOf是可以解析得到結果的。

    public void testNaN(){
        System.out.println(Double.valueOf("NaN"));
        System.out.println(Double.valueOf("Infinity"));
        System.out.println(Double.valueOf("-Infinity"));
    }

運行輸出:

NaN
Infinity
-Infinity

所以,我們還需要額外去判斷NaN和Infinity:

public void correctParse(String userInput){
        double val = 0;
        try {
            val = Double.valueOf(userInput);
        } catch (NumberFormatException e) {
        }
        if (Double.isInfinite(val)){
            // Handle infinity error
        }

        if (Double.isNaN(val)) {
            // Handle NaN error
        }
        //do something for val
    }

不要使用float或者double作為循環的計數器

考慮下面的代碼:

for (float x = 0.1f; x <= 1.0f; x += 0.1f) {
  System.out.println(x);
}

上面的代碼有什么問題呢?

我們都知道java中浮點數是不準確的,但是不一定有人知道為什么不準確。

這里給大家解釋一下,計算機中所有與的數都是以二進制存儲的,我們以0.6為例。

0.6轉成為二進制格式是乘2取整,0.6x2=1.2,取整剩余0.2,繼續上面的步驟0.2x2=0.4,0.4x2=0.8,0.8x2=1.6,取整剩余0.6,產生了一個循環。

所以0.6的二進制格式是.1001 1001 1001 1001 1001 1001 1001 ... 無限循環下去。

所以,有些小數是無法用二進制精確的表示的,最終導致使用float或者double作為計數器是不準的。

BigDecimal的構建

為了解決float或者Double計算中精度缺失的問題,我們通常會使用BigDecimal。

那么在使用BigDecimal的時候,請注意一定不要從float構建BigDecimal,否則可能出現意想不到的問題。

    public void getFromFloat(){
        System.out.println(new BigDecimal(0.1));
    }

上面的代碼,我們得到的結果是:0.1000000000000000055511151231257827021181583404541015625。

這是因為二進制無法完美的展示所有的小數。

所以,我們需要從String來構建BigDecimal:

    public void getFromString(){
        System.out.println(new BigDecimal("0.1"));
    }

類型轉換問題

在java中各種類型的Number可以互相進行轉換:

比如:

  • short to byte or char

  • char to byte or short

  • int to byte, short, or char

  • long to byte, short, char, or int

  • float to byte, short, char, int, or long

  • double to byte, short, char, int, long, or float

或者反向:

  • byte to short, int, long, float, or double

  • short to int, long, float, or double

  • char to int, long, float, or double

  • int to long, float, or double

  • long to float or double

  • float to double

從大范圍的類型轉向小范圍的類型時,我們要考慮是否超出轉換類型范圍的情況:

    public void intToByte(int i){
        if ((i < Byte.MIN_VALUE) || (i > Byte.MAX_VALUE)) {
            throw new ArithmeticException("Value is out of range");
        }
        byte b = (byte) i;
    }

比如上面的例子中,我們將int轉換成為byte,那么在轉換之前,需要先判斷int是否超出了byte的范圍。

同時我們還需要考慮到精度的切換,看下面的例子:

    public void intToFloat(){
        System.out.println(subtraction(1111111111,1111111111));
    }

    public int subtraction(int i , float j){
        return i - (int)j;
    }

結果是多少呢?

答案不是0,而是-57。

為什么呢?

因為這里我們做了兩次轉換,第一次從1111111111轉換到float,float雖然有32位,但是只有23位是存放真正的數值的,1位是符號位,剩下的8位是指數位。

所以從1111111111轉換到float發送了精度丟失。

我們可以把subtraction方法修改一下,首先判斷float的范圍,如果超出了23bit的表示范圍,則說明發送了精度丟失,我們需要拋出異常:

    public int subtraction(int i , float j){
        System.out.println(j);
        if ((j > 0x007fffff) || (j < -0x800000)) {
            throw new ArithmeticException("Insufficient precision");
        }
        return i - (int)j;
    }

當然還有一種辦法,我們可以用精度更高的double來做轉換,double有52位來存放真正的數據,所以足夠了。

    public int subtractionWithDouble(int i , double j){
        System.out.println(j);
        return i - (int)j;
    }

到此,相信大家對“java中的Number怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

上高县| 嵩明县| 诏安县| 彩票| 涪陵区| 四会市| 浦北县| 双辽市| 金堂县| 江源县| 洞口县| 吐鲁番市| 惠水县| 务川| 收藏| 淮安市| 仙桃市| 新密市| 蓬溪县| 边坝县| 蒲城县| 日土县| 湖北省| 仁布县| 封开县| 南昌市| 娱乐| 库尔勒市| 勐海县| 宁国市| 迁西县| 龙里县| 江西省| 正安县| 饶阳县| 陕西省| 唐河县| 同德县| 平潭县| 广河县| 长乐市|