NumberFormatException при преобразовании двоичной строки в целое число - PullRequest
0 голосов
/ 04 июля 2018

Я учусь манипулированию битами в 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);

Байт и шорт преобразуются и дают наименьший байт и наименьшее короткое значение, в то время как целое число не конвертируется.

Выдает 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, а целое число - 32-битную в Java, таким образом, она должна работать, хотя здесь это не так.

Если я удаляю одну 0 или 1 из строки длиной 32 или заменяю 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, и решение этой проблемы.

1 Ответ

0 голосов
/ 04 июля 2018

Краткий ответ:

Метод Integer.parseInt () (который является методом, вызываемым Integer.valueOf ()) требует, чтобы вы сообщали ему, является ли число отрицательным, поскольку он не предназначен для обработки чисел со знаком. «Исправьте» свой код, добавив минус:

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

Длинный ответ:

Ваша трассировка стека говорит вам, где вы можете узнать, где что-то пошло не так. Ваш метод Integer.valueOf () вызывает Integer.parseInt (), который, в свою очередь, вызывает исключение NumberFormatException в строке 583. Код для класса Integer можно найти в 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;
}

Я удалил части кода, которые наш текущий пример не выполняет для пояснения. Обратите внимание, что предел -2147483647 (один сверх MIN_VALUE)! Аналогично, multmin -1073741823. В первой итерации цикла результат равен 0, поэтому результат * radix равен 0, а цифра равна 1 (это первое число в нашей строке), поэтому результат - цифра равна -1. Во второй итерации цифра становится 0, но теперь результат * radix равен -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 (), а затем приводит ответ к байту! И поскольку 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 () для чисел со знаком.

...