93

In the Oracle "Primitive data types" page, it mentions that Java 8 adds support for unsigned ints and longs:

int: By default, the int data type is a 32-bit signed two's complement integer, which has a minimum value of −231 and a maximum value of 231−1. In Java SE 8 and later, you can use the int data type to represent an unsigned 32-bit integer, which has a minimum value of 0 and a maximum value of 232−1. Use the Integer class to use int data type as an unsigned integer. See the section The Number Classes for more information. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.

long: The long data type is a 64-bit two's complement integer. The signed long has a minimum value of −263 and a maximum value of 263−1. In Java SE 8 and later, you can use the long data type to represent an unsigned 64-bit long, which has a minimum value of 0 and a maximum value of 264−1. Use this data type when you need a range of values wider than those provided by int. The Long class also contains methods like compareUnsigned, divideUnsigned etc to support arithmetic operations for unsigned long.

However, I find no way to declare an unsigned long or integer. The following code, for example, gives a compiler error message of "the literal is out of range" (I'm using Java 8, of course), when it should be in range (the value assigned is precisely 264−1):

public class Foo {
    static long values = 18446744073709551615L;
    
    public static void main(String[] args){
        System.out.println(values);
    }  
}

So, is there any way to declare an unsigned int or long?

Community
  • 1
  • 1
Pabce
  • 1,429
  • 2
  • 13
  • 12
  • 2
    What is returned in your Long.MAX_VALUE constant in java 8? – Bruno Franco Aug 28 '14 at 18:59
  • 22
    There is no unsigned integer or unsigned long type. If you use one of the new methods, that method will treat a 32-bit or 64-bit integer as though it were unsigned. But that's all. The variable's type will still be signed, and it's up to you to remember that you're using it as an unsigned number. They didn't add unsigned literals, but maybe they'll add them to Java 9 if enough people bug them. :) – ajb Aug 28 '14 at 19:00
  • 5
    They didn't really change anything, other than adding the new methods. – Hot Licks Aug 28 '14 at 19:08
  • 5
    As far as I can tell, all they did was add methods that can return unsigned values, but don't allow you to declare unsigned values. Kind of silly if you ask me, and a real pain. I wonder if one way would be to use the Integer.divideUnsigned, with one parameter being 1, the other being whatever number you want treated as unsigned. Would work as far as I can tell, but seems to be really silly way of doing things. – cluemein Jan 26 '16 at 18:17
  • @ajb how can I be of any assistance in the "bugging" process to finally see proper unsigned in Java? :) – Matthieu Mar 04 '19 at 20:57

5 Answers5

93

Well, even in Java 8, long and int are still signed, only some methods treat them as if they were unsigned. If you want to write unsigned long literal like that, you can do

static long values = Long.parseUnsignedLong("18446744073709551615");

public static void main(String[] args) {
    System.out.println(values); // -1
    System.out.println(Long.toUnsignedString(values)); // 18446744073709551615
}
Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
kajacx
  • 12,361
  • 5
  • 43
  • 70
  • 5
    An observation I see with this is that the ordering is corrupted. If I were to get an unsigned long from some system (Twitter provides such IDs, by the way) and wanted to sort them, perhaps because I knew them to be chronological, then everything beyond Long.MAX_VALUE will actually show up before 0 as negative with Java's implementation :-(. Instead it appears one must also shift it down such that unsigned 0 maps to signed Long.MIN_VALUE. – David Smiley Sep 09 '16 at 03:37
  • 11
    @DavidSmiley Good point. To sort unsigned longs, use [Long.compareUnsigned](https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html#compareUnsigned-long-long-), or pass that method as a comparator to sort functions, – kajacx Sep 09 '16 at 08:02
55

Per the documentation you posted, and this blog post - there's no difference when declaring the primitive between an unsigned int/long and a signed one. The "new support" is the addition of the static methods in the Integer and Long classes, e.g. Integer.divideUnsigned. If you're not using those methods, your "unsigned" long above 2^63-1 is just a plain old long with a negative value.

From a quick skim, it doesn't look like there's a way to declare integer constants in the range outside of +/- 2^31-1, or +/- 2^63-1 for longs. You would have to manually compute the negative value corresponding to your out-of-range positive value.

Sbodd
  • 11,279
  • 6
  • 41
  • 42
27
    // Java 8
    int vInt = Integer.parseUnsignedInt("4294967295");
    System.out.println(vInt); // -1
    String sInt = Integer.toUnsignedString(vInt);
    System.out.println(sInt); // 4294967295

    long vLong = Long.parseUnsignedLong("18446744073709551615");
    System.out.println(vLong); // -1
    String sLong = Long.toUnsignedString(vLong);
    System.out.println(sLong); // 18446744073709551615

    // Guava 18.0
    int vIntGu = UnsignedInts.parseUnsignedInt(UnsignedInteger.MAX_VALUE.toString());
    System.out.println(vIntGu); // -1
    String sIntGu = UnsignedInts.toString(vIntGu);
    System.out.println(sIntGu); // 4294967295

    long vLongGu = UnsignedLongs.parseUnsignedLong("18446744073709551615");
    System.out.println(vLongGu); // -1
    String sLongGu = UnsignedLongs.toString(vLongGu);
    System.out.println(sLongGu); // 18446744073709551615

    /**
     Integer - Max range
     Signed: From −2,147,483,648 to 2,147,483,647, from −(2^31) to 2^31 – 1
     Unsigned: From 0 to 4,294,967,295 which equals 2^32 − 1

     Long - Max range
     Signed: From −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, from −(2^63) to 2^63 − 1
     Unsigned: From 0 to 18,446,744,073,709,551,615 which equals 2^64 – 1
     */
blueberry0xff
  • 3,707
  • 30
  • 18
22

There is no way how to declare an unsigned long or int in Java 8 or Java 9. But some methods treat them as if they were unsigned, for example:

static long values = Long.parseUnsignedLong("123456789012345678");

but this is not declaration of the variable.

1ac0
  • 2,875
  • 3
  • 33
  • 47
  • 4
    i wounder why not. they could have easily added uint and ulong types – EKanadily Jan 02 '16 at 15:21
  • @docesam in [this](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) and [this](https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html) docu is detailed explanation. in short, just a methods for unsigned manipulation to Integer class has been added. and if they *could have easily added* i don't know why they won't do it ;-) – 1ac0 Jan 03 '16 at 20:22
  • @ Ladislav DANKO there are prudent people , and there are the other guys. i am not sure if - in this case - it was prudent or not, but it is my impression that oracle is not so prudent. – EKanadily Jan 04 '16 at 20:21
  • 1
    @docesam No, they could not have "easily added uint and ulong types". That would require overhauling the JLS, JVM spec, JNI, a lot of libraries (like java.util.Arrays), reflection, and so so much more. – Nayuki Oct 15 '16 at 14:32
  • I argue that there unsigned integers in Java are unnecessary complexity with little expressive benefits: https://www.nayuki.io/page/unsigned-int-considered-harmful-for-java – Nayuki Oct 15 '16 at 14:32
  • 1
    @Michaelangel007 Hey there, I think we're approaching this topic with different background assumptions. Care to shoot me an email and we'll talk about the details? – Nayuki Feb 03 '17 at 23:18
  • 1
    @Nayuki Do you _actually understand the difference_ between signed shift right vs unsigned shift right?? Hint: One sign extends, the other zero extends. Cluttering up the code and masks (i.e. & 0x7FFFFFFF) is just that -- unnecessary clutter because pre Java 8 the language was brain dead. – Michaelangel007 Feb 08 '17 at 18:21
5

If using a third party library is an option, there is jOOU (a spin off library from jOOQ), which offers wrapper types for unsigned integer numbers in Java. That's not exactly the same thing as having primitive type (and thus byte code) support for unsigned types, but perhaps it's still good enough for your use-case.

import static org.joou.Unsigned.*;

// and then...
UByte    b = ubyte(1);
UShort   s = ushort(1);
UInteger i = uint(1);
ULong    l = ulong(1);

All of these types extend java.lang.Number and can be converted into higher-order primitive types and BigInteger.

(Disclaimer: I work for the company behind these libraries)

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509