簡體   English   中英

將二進制字符串轉換為整數時出現 NumberFormatException

[英]NumberFormatException while converting binary string to integer

我正在學習java中的位操作。 所以,我將二進制字符串轉換為整數字節和短。 這是我的程序:-

byte sByte,lByte; // 8 bit
short sShort,lShort; // 16 bit
int sInt,lInt; // 32 bit
sByte= (byte)(int)Integer.valueOf("10000000", 2); //Smallest Byte
lByte= (byte) ~sByte;
sShort= (short)(int)Integer.valueOf("1000000000000000", 2); //Smallest Short
lShort = (short) ~sShort;
sInt = (int) (int)Integer.valueOf("10000000000000000000000000000000", 2); //Smallest Int
lInt= (int)~sInt;
System.out.println("\"10000000\" \"8 bit\" byte=>"+sByte+"\t~byte=>"+lByte);
System.out.println("\"1000000000000000\" \"16 bit\" short=>"+sShort+"\t~short=>"+lShort);
System.out.println("\"10000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);

Byte 和 Short 正在轉換並給出最小的 Byte 和最小的 Short Value,而 Integer 沒有得到轉換。

它拋出 NumberFormatException 如下:-

Exception in thread "main" java.lang.NumberFormatException: For input string: "10000000000000000000000000000000"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:583)
    at java.lang.Integer.valueOf(Integer.java:740)
    at com.learnjava.BitsManipulation.start(BitsManipulation.java:14)
    at com.learnjava.learnjava.main(learnjava.java:9)

如果我評論那 3 個整數轉換行:-

//    sInt = (int) (int)Integer.valueOf("10000000000000000000000000000000", 2); //Smallest Int
//    lInt= (int)~sInt;
//    System.out.println("\"10000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);

它給了我輸出:-

"10000000" "8 bit" byte=>-128   ~byte=>127
"1000000000000000" "16 bit" short=>-32768   ~short=>32767

很好。我已經檢查了兩次字符串的長度,長度為 32,整數在 java 中是 32 位,這樣它應該可以工作,而這里不是這種情況。

如果我從 32 長度的字符串中刪除一個 0 或 1 或將 1 替換為 0,那么它也可以工作,如下所示:-

sInt = (int) (int)Integer.valueOf("00000000000000000000000000000000", 2); //Smallest Int
lInt= (int)~sInt;
System.out.println("\"00000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);


sInt = (int) (int)Integer.valueOf("1000000000000000000000000000000", 2); //Smallest Int
lInt= (int)~sInt;
System.out.println("\"1000000000000000000000000000000\" \"31 bit\" int=>"+sInt+"\t~int=>"+lInt);

輸出如下: -

"00000000000000000000000000000000" "32 bit" int=>0  ~int=>-1

"1000000000000000000000000000000" "31 bit" int=>1073741824  ~int=>-1073741825

我對此感到困惑。 請告訴我它拋出 NumberFormatException 的原因以及此問題的解決方案。

簡短答案:

Integer.parseInt()方法(由Integer.valueOf()調用的方法)要求您告訴該數字是否為負數,因為它不是設計用來處理帶符號的數字。 通過添加減號“修復”您的代碼:

Integer sInt = Integer.valueOf("-10000000000000000000000000000000", 2);
System.out.println(sInt); // prints -2147483648

長答案:

您的stacktrace告訴您在哪里可以找到問題所在。 您的Integer.valueOf()方法調用Integer.parseInt(),后者又在第583行上引發NumberFormatException。您可以在openjdk中找到Integer類的代碼。

public static int parseInt(String s, int radix) throws NumberFormatException {
    int result = 0;
    int i = 0, len = s.length();
    int limit = -Integer.MAX_VALUE;
    int multmin;
    int digit;

    if (len > 0) {
        char firstChar = s.charAt(0);
        if (firstChar < '0') { // Possible leading "+" or "-"
            if (firstChar == '-') {
                negative = true;
                limit = Integer.MIN_VALUE;
            } else if (firstChar != '+')
                throw NumberFormatException.forInputString(s);
        }

        multmin = limit / radix;
        while (i < len) {
            digit = Character.digit(s.charAt(i++),radix);
            if (result < multmin) {
                throw NumberFormatException.forInputString(s);
            }
            result *= radix;
            result -= digit;
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
    return negative ? result : -result;
}

為了清楚起見,我已經刪除了我們當前示例未運行的部分代碼。 請注意,限制為-2147483647(超過MIN_VALUE的一個)! 同樣,multmin為-1073741823。 在循環的第一次迭代中,結果為0,因此result * radix為0,數字為1(這是我們字符串中的第一個數字),因此結果-數字為-1。 在第二次迭代中,digit變為0,但是現在結果*基數為-2。 在第三次迭代中,我們得到-4,然后得到-8,依此類推...一直進行到結果等於-1073741824,這比我們的極限小一。

現在,我們還可以看到該方法檢查是否在數字上添加了符號(+或-)。 有趣的是,如果我們加上減號,我們會看到該限制設置為MIN_VALUE。 因此,違反直覺,我們可以通過添加減號來簡單地“修復”您的代碼:

Integer sInt = Integer.valueOf("-10000000000000000000000000000000", 2);
System.out.println(sInt); // prints -2147483648

另一方面,您在此處進行了一些奇怪的轉換。 代替:

sByte= (byte)(int)Integer.valueOf("10000000", 2);

您應該能夠寫:

sByte = Byte.valueOf("10000000", 2);

我說“應該”,因為實際上你做不到。 這導致另一個異常! 這是因為Byte.valueOf()方法只調用Integer.valueOf()方法,然后將答案轉換為Byte! 並且因為整數的10000000為000 ... 00010000000 = 128,它將告訴您對於一個字節來說太大了。

哇! 那么,為什么您怪異的鑄造技巧起作用了? 因為所謂的“無聲溢出”。 Java意識到您迫切希望將數字128容納在一個字節中,這是不可能的,因此它將盡可能多的數字放入其中(127),並通過添加其余的1環繞到底部,使您得到-128 。 我想這就是設計靜默溢出的目的,但是依賴它絕對不是一個好主意。 為了說明您的行中發生的情況:

sByte= (byte)(int)Integer.valueOf("10000000", 2);

Integer a = Integer.valueOf("10000000", 2);
System.out.println(a);        // 128
int b = (int)a;
System.out.println(b);        // 128
byte sByte = (byte)b;
System.out.println(sByte);    // -128

因此,請勿在帶符號的數字上使用parseInt()或valueOf()。

在 kotlin 中像這樣轉換為 Long 然后 long 轉換為 Int

try {
    val binaryString = "10010100101111111111000010100001"
    if (binaryString.isEmpty()) println("number is empty")
    else {
        val number = binaryString.toLong(2)
        println("number is ${number.toInt()}")
  }

} catch (e: Exception) {
    e.stackTrace.forEach {
        kotlin.io.println("number is ${it.toString()}")
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM