8
public class Main3 {
    public static void main(String[] args) {
        Integer min = Integer.MIN_VALUE;
        String minHex = Integer.toHexString(Integer.MIN_VALUE);

        System.out.println(min + " " + minHex);
        System.out.println(Integer.parseInt(minHex, 16));
    }
}

Gives

-2147483648 80000000
Exception in thread "main" java.lang.NumberFormatException: For input string: "80000000"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:459)
    at Main3.main(Main3.java:7)

Whats up?

Gurwinder Singh
  • 38,557
  • 6
  • 51
  • 76
Maxim Veksler
  • 29,272
  • 38
  • 131
  • 151

7 Answers7

13

It's documented that Integer.toHexString returns a string representation of the integer as an unsigned value - while Integer.parseInt takes a signed int. If you use Integer.toString(value, 16) instead you'll get what you want.

Gurwinder Singh
  • 38,557
  • 6
  • 51
  • 76
dhn
  • 196
  • 1
  • 4
  • it would have been cool if there was a method to convert from hex to int/long just placing bits without caring about sign. That way it would have been possible to convert back and forth with minimal overhead. – akostadinov Mar 28 '13 at 10:13
13

This is something that's always annoyed me. If you initialize an int with a hex literal, you can use the full range of positive values up to 0xFFFFFF; anything larger than 0x7FFFFF will really be a negative value. This is very handy for bit masking and other operations where you only care about the locations of the bits, not their meanings.

But if you use Integer.parseInt() to convert a string to an integer, anything larger than "0x7FFFFFFF" is treated as an error. There's probably a good reason why they did it that way, but it's still frustrating.

The simplest workaround is to use Long.parseLong() instead, then cast the result to int.

int n = (int)Long.parseLong(s, 16);

Of course, you should only do that if you're sure the number is going to be in the range Integer.MIN_VALUE..Integer.MAX_VALUE.

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
6

According the the documentation, toHexString returns "a string representation of the integer argument as an unsigned integer in base 16. "

So the correct reverse operation is probably Integer.parseUnsignedInt that was introduced as part of Java 8:

public class Main3 {
    public static void main(String[] args) {
        Integer min = Integer.MIN_VALUE;
        String minHex = Integer.toHexString(Integer.MIN_VALUE);

        System.out.println(min + " " + minHex);
        System.out.println(Integer.parseUnsignedInt(minHex, 16));
    }
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
2

Try this:

public class Main3 {
    public static void main(String[] args) {
        Integer min = Integer.MIN_VALUE;
        String minHex = Integer.toHexString(Integer.MIN_VALUE);

        System.out.println(min + " " + minHex);
        System.out.println(Integer.parseInt( "-" + minHex, 16));
    }

}

to get this:

-2147483648 80000000
-2147483648
alphazero
  • 27,094
  • 3
  • 30
  • 26
1

You need to include a negative sign.

I don't have access to test this right now but I'd bet if you tried this value instead:

Integer min = Integer.MIN_VALUE + 1;

It wouldn't bomb, but would give you a positive number (not negative) when you ran ParseInt(min,16).

A string of bits doesn't really have enough info to determine sign in this context so you need to provide it. (consider the case where you use min = "F". Is that +/-F? If you converted it to bits and saw 1111, and you knew it was a byte, you might conclude that it's negative, but that's a lot of ifs.

Michael Haren
  • 105,752
  • 40
  • 168
  • 205
0

This seem to work for me :

public class Main3 {
public static void main(String[] args) {
    Integer min = Integer.MIN_VALUE;
    String minHex = Integer.toHexString(Integer.MIN_VALUE);

    System.out.println(min + " " + minHex);
    System.out.println((int)Long.parseLong(minHex, 16));
}
}

The integer is parsed as a "signed long" that handle such big positive number and then the sign is found back by casting it to "int".

Fabrice LARRIBE
  • 322
  • 3
  • 9
0

Integer.parseInt() takes in a signed integer as it's input. This means the input has to be between "7FFFFFFF" and "-80000000". Note the negative sign before "80000000". What you want is Integer.parseInt("-80000000", 16). If you use 80000000 without the minus sign Java will interpret that as a positive number and throw an exception because the max positive integer for an int is 0x7FFFFFFF.