Recently, when I was working with jhammer, I discovered a frustrating ‘feature’ of some of the default Java Integer and Long methods. I hope to save some other coders the same trouble. The problem comes down to this:
Integer.parseInt(Integer.toHexString(i),16) != i;
When the integer i has the most significant bit set (i.e. 0×80000000) , parseInt will throw a NumberFormatException. I don’t think this is a problem with the methods or their implementation, but rather is a result of Java’s lack of support for ‘unsigned’ integers. i.e. – a 32 bit integer is ranged from -0×40000000 to 0×40000000, with the upper-most bit being the ’sign’ bit. This would be okay, except for the Integer.toHexString method returns a (hexidecimal) string that represents an unsigned 32-bit integer: The string form of 0xa0000000 (decimal -1610612736, in 2’s compliment) is represented as “0xa0000000″, which is unparsable by Integer.parseInt as it is not (really) a ‘valid’ signed 32-bit integer.
There are two solutions that I came up with:
- Roll your own solution (which is what I did, as it looks better to the user, in my opinion).
- Test the upper-most bit and flip the ’signs’ of the outputted hexadecimal string. It looks something like this:
String prefix = ((value & 1<<31) != 0) ? "-" : ""; String value_str = prefix + Integer.toHexString(-value);
This will create out parsable hexadecimal numbers that will be ‘correct’ 31-bit integers. The same process can be followed to create parsable hexadecimal Longs.
Or you could use Integer.toString(value, 16);
You. Are. Insane.
And it’s probably my fault……