欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

你知道Java判斷字符串是否為數字的多種方式嗎

 更新時間:2022年07月06日 08:38:14   作者:Alphathur  
在編程的時候經常遇到要判斷一個字符串中的字符是否是數字(0-9),所以下面這篇文章主要給大家介紹了關于Java判斷字符串是否為數字的多種方式,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下

前言

判斷一個字符串是否為數字是Java開發(fā)中很常見的業(yè)務需求,實現(xiàn)這個判斷有很多種方式,大體上分為異常處理,正則表達式,數字字符,NumberFormat工具類,外部工具類這五大類,不同類型下的實現(xiàn)方式其實略有不同,那么究竟選擇哪種方式才是最好的呢?本文將一一列舉出這5類中具體8個方案,并通過豐富的測試用例來并對比這些方案的差異,相信看完本文,你將會有自己的思考。

異常處理

使用異常處理的本質是基于java自身對于字符串定義而實現(xiàn)的,如果我們的字符串能夠被轉換為數字,那么這個字符串就是數字,如果轉換失敗則會拋出異常,所以我們如果能夠捕獲異常,就可以認為它不是數字,這個方案很簡單:

    public static boolean isNumeric1(String str) {
        try {
            Double.parseDouble(str);
            return true;
        } catch(Exception e){
            return false;
        }
    }

如果我們的業(yè)務只要求判斷字符串是否為整數,那么只需要將Double.parseDouble(str);換成Integer.parseInt(str);即可。但是這個方案有個致命缺陷,由于判斷失敗會拋異常出來,當判斷失敗的頻率比較高,將產生較大的性能損耗。

正則表達式

使用正則表達式也是一種常見的判斷方式,以下的正則表達式將判斷輸入字符串是否為整數或者浮點數,涵蓋負數的情況。

    public static boolean isNumeric2(String str) {
        return str != null && str.matches("-?\\d+(\\.\\d+)?");
    }

當然,為了性能考量,這個方法最好優(yōu)化成以下方式,因為上面的寫法每次調用時都會在matches內部間接創(chuàng)建一個Pattern實例。

    private static final Pattern NUMBER_PATTERN = Pattern.compile("-?\\d+(\\.\\d+)?");
    public static boolean isNumeric2(String str) {
        return str != null && NUMBER_PATTERN.matcher(str).matches();
    }

使用NumberFormat

通常使用NumberFormat類的format方法將一個數值格式化為符合某個國家地區(qū)習慣的數值字符串,例如我們輸入18,希望輸出18¥,使用這個類再好不過了,這里可以了解它的具體用法。但是也可以用該類的parse方法來判斷輸入字符串是否為數字。

    public static boolean isNumeric3(String str) {
        if (str == null) return false;
        NumberFormat formatter = NumberFormat.getInstance();
        ParsePosition pos = new ParsePosition(0);
        formatter.parse(str, pos);
        return str.length() == pos.getIndex();
    }

數字字符

字符串的底層實現(xiàn)其實就是字符數組,如果這個字符數組中每個字符都是數字,那么這個字符串不就是數字字符串了嗎?利用java.lang.Character#isDigit(int)判斷所有字符是否為數字字符從而達到判斷數字字符串的目的:

    public static boolean isNumeric4(String str) {
        if (str == null) return false;
        for (char c : str.toCharArray ()) {
            if (!Character.isDigit(c)) return false;
        }
        return true;
    }

如果你的java版本是8以上,以上的寫法可以替換成如下Stream流的方式,從而看起來更優(yōu)雅。所以,茴香豆的‘茴’又多了一種寫法!

    public static boolean isNumeric4(String str) {
        return str != null && str.chars().allMatch(Character::isDigit);
    }

外部工具類

使用外部工具類通常需要引入外部jar文件,一般的依賴是apache的comons-lang:

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

在使用外部工具類時,我們通常使用NumberUtils或者StringUtils,具體如下:

使用NumberUtils時,我們通常會選擇其靜態(tài)方法isParsable和isCreatable其中的一種,它們的不同點在于isCreatable不僅可以接受十進制數字字符串,還可以接受八進制,十六進制以及科學計數法表示的數字字符串,isParsable只接受十進制數字字符串。

1.NumberUtils.isParsable

    public static boolean isNumeric5(String str) {
        return NumberUtils.isParsable(str);
    }

2.NumberUtils.isCreatable

    public static boolean isNumeric6(String str) {
        return NumberUtils.isCreatable(str);
    }

如果使用StringUtils,那么要考慮到底該使用isNumeric還是isNumericSpace。二者的唯一差異在于,isNumeric會認為空字符串為非法數字,isNumericSpace則認為空字符串也是數字。

3.StringUtils.isNumeric

    public static boolean isNumeric7(String str) {
        return StringUtils.isNumeric(str);
    }

4.StringUtils.isNumericSpace

    public static boolean isNumeric8(String str) {
        return StringUtils.isNumericSpace(str);
    }

測試并比較

默認情況下,文章中的數字都指的是十進制的阿拉伯數字(0 ,1,2 … 9),測試時會擴展范圍??紤]以下幾個方向:

1)null或者空字符串

2)常規(guī)的數字,整數,浮點數以及負數

3)包含非法的字符,例如包含多余的小數點,包含多余的負號,以及其它非常規(guī)格式

4)非阿拉伯數字,例如印度數字 ???,阿拉伯文 ???,以及羅馬數字Ⅰ、Ⅱ、Ⅲ

5)非十進制的數字,例如二進制,八進制,十六進制,科學計數法表示的數字

主體測試方法如下:

    public static void check(String str) {
        System.out.println ( "----------checking:【" + str + "】---------" );
        System.out.println(isNumeric1(str));
        System.out.println(isNumeric2(str));
        System.out.println(isNumeric3(str));
        System.out.println(isNumeric4(str));
        System.out.println(isNumeric5(str));
        System.out.println(isNumeric6(str));
        System.out.println(isNumeric7(str));
        System.out.println(isNumeric8(str));
        System.out.println( "---------------end-------------------" );
    }

測試用例:

    public static void main(String[] args) throws ParseException {
        //1)null或者空字符串
        check(null);
        check("");
        check(" ");

        //2)正常的數字,整數或者浮點數
        check("123");
        check("0.123");
        check("-12.3");
        check("07");   //普通十進制7 or 八進制7

        //3)包含非法的字符,例如包含多余的小數點,包含多余的負號,以及其它非常規(guī)格式
        check("123.");
        check(".123");
        check("1.2.3");
        check("--12.3");
        check("-1-2.3");
        check("-12.3-");
        check(" 123");
        check("1 23");
        check("123 ");
        check("1a2b3c");
        check("10.0d");  //double類型
        check("1000L");  //long類型
        check("10.0f");  //float類型

        //4)非阿拉伯數字,例如印度數字 ???,阿拉伯文 ???,以及羅馬數字Ⅰ、Ⅱ、Ⅲ
        check("???");
        check("???");
        check("Ⅲ");

        //5)非十進制的數字,例如二進制,八進制,十六進制,科學計數法表示的數字
        check("0b100");  //二進制
        check("09");     //十進制9 or 非法的八進制
        check("0xFF");   //十六進制
        check("2.99e+8");//科學計數法
    }

由于篇幅原因,這里就不將控制臺的打印結果貼上來了,有興趣的同學可以根據我的代碼自己嘗試一下。

下面是將測試用例的打印結果做了個表格匯總,表頭為方法名,第一列是具體的輸入字符串,表格中其它單元格表示該方法判斷是否為數字字符串的結果。

用例isNumberic1isNumberic2isNumberic3isNumberic4isNumberic5isNumberic6isNumberic7isNumberic8
nullfalsefalsefalsefalsefalsefalsefalsefalse
“”falsefalsetruetruefalsefalsefalsetrue
" "falsefalsefalsefalsefalsefalsefalsetrue
“123”truetruetruetruetruetruetruetrue
“0.123”truetruetruefalsetruetruefalsefalse
“-12.3”truetruetruefalsetruetruefalsefalse
“07”truetruetruetruetruetruetruetrue
“123.”truefalsetruefalsefalsetruefalsefalse
“.123”truefalsetruefalsetruetruefalsefalse
“1.2.3”falsefalsefalsefalsefalsefalsefalsefalse
“–12.3”falsefalsefalsefalsefalsefalsefalsefalse
“-1-2.3”falsefalsefalsefalsefalsefalsefalsefalse
“-12.3-”falsefalsefalsefalsefalsefalsefalsefalse
" 123"truefalsefalsefalsefalsefalsefalsetrue
“1 23”falsefalsefalsefalsefalsefalsefalsetrue
"123 "truefalsefalsefalsefalsefalsefalsetrue
“1a2b3c”falsefalsefalsefalsefalsefalsefalsefalse
“10.0d”truefalsefalsefalsefalsetruefalsefalse
“1000L”falsefalsefalsefalsefalsetruefalsefalse
“10.0f”truefalsefalsefalsefalsetruefalsefalse
“???”falsefalsetruetruetruefalsetruetrue
“???”falsefalsetruetruetruefalsetruetrue
“Ⅲ”falsefalsefalsefalsefalsefalsefalsefalse
“0b100”falsefalsefalsefalsefalsefalsefalsefalse
“09”truetruetruetruetruefalsetruetrue
“0xFF”falsefalsefalsefalsefalsetruefalsefalse
“2.99e+8”truefalsefalsefalsefalsetruefalsefalse

通過這個表格,可以看出不同的判斷方法,對于非常規(guī)的字符串來說,差異還是比較大的。

1)null或者空字符串

在處理null時所有方法保持一致,這也是一個工具類該滿足的基本素養(yǎng)。

對于空字符串來說,無論空字符串長度是否大于0,基于StringUtils.isNumericSpace的isNumberic8均會返回true,因為它本身認為空字符串就是數字。

對于長度大于0的空字符串來說,基于NumberFormat的isNumberic3和基于java.lang.Character#isDigit(int)的isNumberic4 這兩種判斷方法都正常返回了false。

但是對于長度為0的空字符串來說,isNumberic3和isNumberic4 這兩種判斷方法出了點小插曲,它們返回了false。這是因為,對于isNumberic3來說,toCharArray或者chars方法返回長度為0的字符數組,它并沒有做一個有效的遍歷。對于isNumberic4來說,NumberFormat的起始位置和終點位置一致。

所以為了讓isNumberic3和isNumberic4更加健壯,建議對其實現(xiàn)內部再加一層空字符串的判斷,優(yōu)化后的代碼如下。

    public static boolean isNumeric3(String str) {
        if (str == null || str.trim ().length() == 0) return false;
        NumberFormat formatter = NumberFormat.getInstance();
        ParsePosition pos = new ParsePosition(0);
        formatter.parse(str, pos);
        return str.length() == pos.getIndex();
    }
    public static boolean isNumeric4(String str) {
        if (str == null || str.trim ().length() == 0) return false;
        for (char c : str.toCharArray ()) {
            if (!Character.isDigit (c)) return false;
        }
        return true;
    }

2)常規(guī)的數字,整數,浮點數以及負數

常規(guī)數字指業(yè)務中常用的數字,譬如用于表示金額的浮點數,用于統(tǒng)計數量的整數等。這種情況下,isNumberic1,isNumberic2,isNumberic3,isNumberic5,isNumberic6 均表現(xiàn)出一致性,它們判斷出來的結果都是相同的,而且也是符合我們常規(guī)預期的,是我們認為正確的結果。

對于浮點數,isNumberic4認為這不是有效數字,因為java.lang.Character#isDigit(int)認為小數點并不是數字字符。同樣的,基于StringUtils.isNumeric的 isNumberic7 和基于StringUtils.isNumericSpace的 isNumberic8 也返回了false。

如果我們查看以上兩個方法的底層實現(xiàn),就可以發(fā)現(xiàn) isNumberic7,isNumberic8 和 isNumberic4 的底層實現(xiàn)邏輯都是一樣的,它們都是通過判斷字符是否為數字字符來實現(xiàn)的。以下是StringUtils.isNumeric和StringUtils.isNumericSpace的源碼:

    public static boolean isNumeric(CharSequence cs) {
        if (isEmpty(cs)) {
            return false;
        } else {
            int sz = cs.length();

            for(int i = 0; i < sz; ++i) {
                if (!Character.isDigit(cs.charAt(i))) {
                    return false;
                }
            }

            return true;
        }
    }

    public static boolean isNumericSpace(CharSequence cs) {
        if (cs == null) {
            return false;
        } else {
            int sz = cs.length();

            for(int i = 0; i < sz; ++i) {
                if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
                    return false;
                }
            }

            return true;
        }
    }

這里尤其注意 “07“這個字符串。在某些語境下,07是十進制的7,在另一些語境下,07是八進制的7。例如我們直接將07賦值個int變量,它確實可以通過編譯,但是把07換成09呢?一定會編譯失敗,這是因為變量聲明的場景下,07作為八進制對待,它滿足八進制的范圍要求,而八進制無法表示09,它太大了,所以編譯失敗。

但是Double.parseDouble卻可以將“09”轉化成9.0,因為這種場景下,輸入的數字作為十進制對待,0被忽略了。

        int j = 07;
        int k = 09;   //編譯失敗,非法的八進制
        System.out.println (Double.parseDouble ("09")); //打印9.0,以十進制對待

盡管以0開頭的數字字符串,在使用Double.parseDouble 的語境中被當作十進制對待,可以被正確解析。但是從某些業(yè)務角度或者某種特定思維上來說,數字怎么能以0開始呢?你能接受一個以0開頭的整數或者浮點數嗎?如果你不能接受這是一個合法的數字字符串,那么很遺憾,現(xiàn)有的案例均不滿足需求。你似乎只能通過正則表達式來實現(xiàn),重新定義你的正則表達式,來過濾掉這類不恰當的字符串。

同時還需要注意,表格倒數第三行的用例是“09”,和“07”這一行類似,但isNumberic6在這兩行表現(xiàn)的不一致。這是由于isNumberic6使用了NumberUtils.isCreatable,它把以“0”開頭的數字認為是八進制數,符合八進制范圍的返回true,不符合的返回false。所以"07"會返回true,“09”會返回false。

特別注意,當輸入為“10.0d”, “1000L”和“10.0f”時,在某種程度上也認為這是有效的數字,因為基本類型中聲明double,long和float類型的變量時,分別在字面量后面添加一個‘d’(‘D’) ,‘l’(‘L’) 和 ‘f’(‘F’)是一個很常見的操作。 這類聲明一般用來處理強制轉換,但對于這類數字字符串來說,使用 isNumberic1 的局限性就出來了,本例中基于 Double.parseDouble 來做判斷,它可以接受‘d’(‘D’) 和 ‘f’(‘F’) 結尾的數字字符串,但是不能接受以 ‘l’(‘L’) 結尾的數字字符串,以下是Double.parseDouble的部分源碼片段。

if (var6 >= var5 || var6 == var5 - 1 && (var0.charAt(var6) == 'f' || var0.charAt(var6) == 'F' || var0.charAt(var6) == 'd' || var0.charAt(var6) == 'D')) {
    if (var13) {
        return var1 ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
    }

    return new FloatingDecimal.ASCIIToBinaryBuffer(var1, var3, var21, var8);
}

那是不是意味著,如果我們將isNumberic1的內部實現(xiàn)換成Long.parseLong,它就可以接受 “1000L” 了呢?答案是否定的,如果我們運行以下的代碼,系統(tǒng)將拋出異常。

System.out.println (Long.parseLong ("5562L"));

這是因為Long.parseLong的底層還是用到了Character.digit方法。以下是Long.parseLong的部分源碼片段,上述的打印將在第一個”if“塊拋出異常。

            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(s.charAt(i++),radix);
                if (digit < 0) {
                    throw NumberFormatException.forInputString(s);
                }
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s);
                }
                result -= digit;
            }

因此,如果你需要接受以‘d’(‘D’),‘f’(‘F’) 和 ‘l’(‘L’)結尾的數字字符串,只有isNumberic6是最優(yōu)解。

3)包含非法的字符,例如包含多余的小數點,包含多余的負號,以及其它非法格式

這部分的用例就相對靈活很多了。極端情況下,比如多一個小數點,或者多一個負號,或者純粹的摻入非數字字符,isNumberic1 ~ isNumberic8均能做出有效的判斷。

但是,如果只有一個小數點,且小數點的位置不合時宜的情況下,比如“123.”,“.123”,使用異常處理的isNumberic1和使用NumberFormat的isNumberic3行為一致,均返回了true。

你可能驚呆了,這怎么能算是有效字符串呢,這種情況其實和07這個測試用例是一樣的,Java可以將它們轉換成浮點數123.0或者整數123。所以返回true對于java來說這就是合理的。如果你不滿意,那只能考慮正則這條路了。

4)非阿拉伯數字,例如印度數字 ???,阿拉伯文 ???,以及羅馬數字Ⅰ、Ⅱ、Ⅲ

所有的判斷方法,均認為羅馬數字為非法數字。

使用印度數字或者阿拉伯文數字,其中 isNumberic3,isNumberic4,isNumberic5,isNumberic7,isNumberic8 能夠做出有效判斷。其它方案均無效。

如果是做國際業(yè)務的同學,你可能就要留意了,他們用本地語言填寫的電話號碼你涵蓋了嗎?

等等,那漢字表示的數字,“一”,“二”,“三”… 該用什么方法來判斷呢? 很遺憾,本文列舉的方法均不滿足,需要自己開發(fā)相關工具類或查找有效資料。

5)非十進制的數字,例如二進制,八進制,十六進制,科學計數法表示的數字

前面的測試用例均是十進制數,但是一些少數場景不免會出現(xiàn)十進制以外的數據。二進制變量以 0b或0B 開始,八進制以 0開始,十六進制以0X或0x開始。

通過倒數第二行和倒數第三行可以看出來,只有 isNumberic6 可以準確的判斷出八進制和十六進制。

通過倒數第四行可以看出來,任何方法都不能判斷二進制。

通過最后一行可以看出來,isNumberic1和isNumberic6 可以用來判斷科學計數法。

小結

判斷一個字符串是否為數字看起來是一項很簡單的業(yè)務,但是它涉及的場景卻是非常多的,從業(yè)務角度來看,沒有哪個方法是完美的。

有人說異常處理的方式不好,性能低,但是它能處理開頭和結尾為空字符串的輸入,還能處理科學計數法。

有人說正則最好,但他們用的正則表達式基本都是從網上扒下來的吧,只能判斷阿拉伯數字吧,而且不能處理以0開始的字符吧。

有人說使用數字字符的方式最好,但是它無法判斷浮點數。

還有人說使用StringUtils最好,那他們有對比過NumberUtils嗎?

總之,沒有什么方法是最好的, 最適合的才是最好的。這就和找對象一個道理,你說劉亦菲美吧,她很美,但不適合呀。

總結

到此這篇關于Java判斷字符串是否為數字多種方式的文章就介紹到這了,更多相關Java判斷字符串是否為數字內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Spring Boot 的創(chuàng)建和運行示例代碼詳解

    Spring Boot 的創(chuàng)建和運行示例代碼詳解

    Spring Boot 的誕生是為了簡化Spring程序的開發(fā),今天給大家介紹下Spring Boot 的創(chuàng)建和運行,主要包括Spring Boot基本概念和springboot優(yōu)點,本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2022-07-07
  • Java中的三元運算(三目運算)以后用得到!

    Java中的三元運算(三目運算)以后用得到!

    Java提供了一個三元運算符,可以同時操作3個表達式,下面這篇文章主要給大家介紹了關于Java中三元運算(三目運算)的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • Java使用pulsar-flink-connector讀取pulsar catalog元數據代碼剖析

    Java使用pulsar-flink-connector讀取pulsar catalog元數據代碼剖析

    這篇文章主要介紹了Java使用pulsar-flink-connector讀取pulsar catalog元數據代碼剖析,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • Mybatis自關聯(lián)查詢一對多查詢的實現(xiàn)示例

    Mybatis自關聯(lián)查詢一對多查詢的實現(xiàn)示例

    這篇文章主要介紹了Mybatis自關聯(lián)查詢一對多查詢的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-02-02
  • 基于Java SSM框架開發(fā)圖書借閱系統(tǒng)源代碼

    基于Java SSM框架開發(fā)圖書借閱系統(tǒng)源代碼

    本文給大家介紹了基于Java SSM框架開發(fā)圖書借閱系統(tǒng),開發(fā)環(huán)境基于idea2020+mysql數據庫,前端框架使用bootstrap4框架,完美了實現(xiàn)圖書借閱系統(tǒng),喜歡的朋友快來體驗吧
    2021-05-05
  • struts2數據處理_動力節(jié)點Java學院整理

    struts2數據處理_動力節(jié)點Java學院整理

    Struts2框架框架使用OGNL語言和值棧技術實現(xiàn)數據的流轉處理。下面通過本文給大家分享struts2數據處理的相關知識,感興趣的朋友參考下吧
    2017-09-09
  • java開發(fā)微信分享接口的步驟

    java開發(fā)微信分享接口的步驟

    這篇文章主要為大家詳細介紹了java開發(fā)微信分享接口的步驟,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • xxl-job 帶參數執(zhí)行和高可用部署方法

    xxl-job 帶參數執(zhí)行和高可用部署方法

    這篇文章主要介紹了xxl-job 帶參數執(zhí)行和高可用部署,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • Spring Boot中l(wèi)ombok的安裝與使用詳解

    Spring Boot中l(wèi)ombok的安裝與使用詳解

    這篇文章主要給大家介紹了關于Spring Boot中l(wèi)ombok安裝與使用的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-09-09
  • mybatis中使用not?in與?in的寫法說明

    mybatis中使用not?in與?in的寫法說明

    這篇文章主要介紹了mybatis中使用not?in與?in的寫法說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01

最新評論