Java in the meantime has gained all the unsigned operations as methods in the Integer and Long classes, so the relatively rare cases when you need them are straightforward to handle.
The only real annoyance is that byte is signed. At least there’s a bit of unsigned support in the Byte class now.
Lastly, minor point, Java actually has an unsigned 16-bit integer type, called char.
The choice of having unsigned types or not is always one of the lesser evil, and in a language where emitting signals directly to hardware ports is not a primary use case, the argument that not having these types is the lesser evil carries a lot of merit.
The risk of unsigned types (even without the C or C++ issues around mixing with signed types) is that too many people make the mistake of using them to express the invariant of "a number that must be positive", which modular arithmetic types are a really bad fit for.
One possible use is for a memory-efficient storage of small positive values, say in a byte. But then you have to make a choice between forcing the value into a signed type for arithmetic (which Java easily lets you do with Byte.toUnsignedInt) and allowing signed and unsigned types to be mixed.
Unsigned integer types are only really necessary when dealing with low-level bit manipulation, but most programs don't do this. The lack of unsigned integers makes low-level stuff a bit more difficult, but it makes the language as a whole much easier. It's a good tradeoff.
Keeping unsigned integer types out of the language makes things much simpler, and keeping things simple was an original design goal of Java.
Mandate 2's complement be used.
> Unsigned integer types are only really necessary when dealing with low-level bit manipulation
They also give one more bit of precision, useful when dealing with 32-bit integers (or below)