NumberFormatException while converting binary string to integer

守給你的承諾、 提交于 2021-01-27 22:01:00

问题


I am learning bit manipulation in java. So,I am converting binary string to integers bytes and short. Here is my program :-

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 and Short are being converting and giving smallest Byte and smallest Short Value while Integer is not getting converted.

It is throwing NumberFormatException which is as follows :-

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)

and if i comment those 3 integer converting lines :-

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

It is giving me output :-

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

which is fine.I have checked length of string twice which is of 32 length and integer is of 32 bit in java in this way it should work while that is not case here.

If i remove one 0 or 1 from 32 length string or replace 1 to 0 then it also works which is as follow :-

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);

output is as follows:-

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

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

i am getting confused on this. Please tell me reason why it is throwing NumberFormatException and solution for this problem.


回答1:


Short answer:

The Integer.parseInt() method (which is a method called by Integer.valueOf()) requires you to tell it if the number is negative, because it is not designed handle signed numbers. "Fix" your code by adding a minus:

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

Long answer:

Your stacktrace tells you where you can find out where things go wrong. Your Integer.valueOf() method calls Integer.parseInt(), which in turn throws a NumberFormatException on line 583. You can find the code for the Integer class in the openjdk.

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;
}

I've removed the parts of the code that our current example does not run through for clarification. Note that limit is -2147483647 (one over the MIN_VALUE)! Likewise, multmin is -1073741823. In the first iteration of the loop, result is 0, so result*radix is 0 and digit is 1 (that's the first number in our String), so result - digit is -1. In the second iteration, digit becomes 0, but now result * radix is -2. In the third iteration, we get -4, then -8, etc... This goes on all the way until result equals -1073741824, which is one fewer than our limit.

Now, we can also see that the method checks if we added a sign (+ or -) to our number. Interestingly, if we do add a minus, we see that limit is set to MIN_VALUE. So, counterintuitively, we can simply "fix" your code by adding a minus:

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

On another note, you do some weird casting there. Instead of:

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

You should be able to write:

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

I Say "should", because actually you can't. This results in another exception! This is because the Byte.valueOf() method simple calls the Integer.valueOf() method and then casts the answer to a Byte! And because 10000000 for an Integer is 000...00010000000 = 128, it will tell you that that is too large for a Byte.

Whoa! So why does your weird casting trick work? Because of a thing called "silent overflow". Java recognizes you desperately want to fit the number 128 in a Byte, which is not possible, so it puts as many as it can into it (127) and it wraps around to the bottom by adding the remaining 1, leaving you with -128. I suppose this is what silent overflow was designed for, but depending on it is definitely a bad idea. To illustrate what happens in your line:

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

So, don't use parseInt() or valueOf() on signed numbers.



来源:https://stackoverflow.com/questions/51167394/numberformatexception-while-converting-binary-string-to-integer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!