> It's much harder to detect a bad unsigned value. You can think of the sign bit as a bad value bit for values that are supposed to be positive.You can also think of NaNs and infinities as bad value markers for values that are almost certainly supposed to be finite values. You can also think of the CPU's overflow flag as a bad value marker for signed arithmetic that wrapped around. In these cases Java happily allows me to compute logically incorrect values (I'm aware of Math.addExact etc.). Such bad value bugs happen, and sure they can often lead to exceptions, but not always, and often not immediately so that they are easy to track down. I still don't think unsigned values are somehow different in this regard and must be checked.
> Those few who wish to work with unsigned types can do so efficiently in Java with the unsigned methods in Integer and Long that were added in JDK 8
Those are helpful because they allow one to get things done, but from the point of view of usability they are the worst of both worlds. They are verbose and unchecked. Porting some tricky crypto or math intrinsic from a specification or a reference C implementation becomes unnecessarily hard: The verbose method names obscure the similarity in the code, and you have no help from the type system to check whether you used the unsigned variants in all the right places. I had the joy of fixing such a bug just a week or two ago.
If I'm doing unsigned arithmetic I need to keep track in my head which values to treat as unsigned. Any later comparison on such values should use Integer.compareUnsigned, but the language doesn't help enforce this. This is exactly what type systems are for. Sure I might still compute wrong unsigned values, bugs happen. But at least I would be applying the intended operations. Telling users to go ahead and compute unsigned values but then allowing them to apply logically incorrect operations on them is actually dangerous. Here you're suddenly not so convinced that the language should be strict?
> A popular library may choose to return sizes as unsigned values
Unlikely. If there are no implicit conversions between signed and unsigned, there's not much you could actually do with such values without lots of casts, unlike in C and C++. Users would rightly complain about making the library harder to use for no benefit. I don't see this happening.
In fact, almost the only thing you could easily do with such a size is do arithmetic on it and then pass the result back into the library as an index. If you got things wrong, the library will throw an IndexOutOfBoundsException. This is exactly what you said why it's OK for signed index calculations to become negative, because "most uses would result in an immediate exception". This would be just as easy or hard to debug as an AIOOBE due to signed arithmetic going wrong.
Anyway. I know I won't change your mind. I get that the feature is not important enough to change the language spec. It's just not worth it? OK, sure. But I don't buy the safety argument.