L Foster wrote:* There is no unsigned. There are only signed byte, int, short, and long values. This can be impactful if you have to interface with other languages via JNI (including the use of OpenGL).
This is my biggest sense of a limitation in Java, because I do image processing. The (endless, it sometimes seems) justifications for the absence of unsigned native types all appear to come from (surprise!) people who don't need them for whatever it is they do. They tend to write off the need for unsigneds as being confined to people who do network programming or file system work (as though neither of those things really matters, but just try to use your computer without a network or a file system). Those of us who fiddle with pixels at an intimate level
really feel the impact of not having unsigned bytes, but I have yet to see even one Java apologist indicate awareness of image processing. They always mention networks and file systems, and then jump to arrogant speeches about how unsigned types are too confusing for programmers to really understand, so the benevolent Java overlords decided to save us from our ignorance and not let us play with toys that we would only use to hurt ourselves. It's a crock and a truly bad move, but we're stuck with it.
L also mentioned the lack of direct pointers. Again, if you do image processing, that's kind of annoying. Now, L also mentioned JNI, which I use a lot. If you need to manipulate an image, using unsigned bytes and real pointers, one way is to write your image processing code in C, and simply "jump" the bridge from Java into C, do your image work there, and jump back. Alas, the JNI is a bit complicated. Once you master it, you can almost ignore it, but it is a bit hard to master. Maybe that's because not a lot of programmers use it (because it is hard to master

), so good guidance on using it is hard to find.
I bring up the JNI in particular, and in connection with image processing, for another reason, though: If your image originates in Java, and you want C to process it, you don't avoid the problem of copying the image buffer just because you used C. The Java standard library includes methods for passing big buffers to C (or whatever language you use to do your JNI work), and, allegedly, you can pin down that buffer so it won't move while your C code expects it to stay in one place. That part works fine, but the library also lets you at least ask to have the buffer passed directly, not as a copy. Alas, you can only ask, not compel. When you pass a big buffer and ask that it not be copied, you can also query to see if you got the actual, original buffer, or a copy of it. Every single program I have written indicates that I always get copies. This means that, if I want to pass a 1280x720 image, with four bytes per pixel, I incur the needless overhead of copying about 3.7 megabytes from Java to C, then copying another 3.7 megabytes from C back to Java, for every image. If you do real-time video work (like I do), that's not trivial. It takes about a millisecond, each way, and I only have 33-1/3 milliseconds before the next frame arrives. Losing 6% of my time to pointless copying is maddening, especially when the library writers knew enough to let me at least ask to avoid it (implying they understood there were reasons a person would want to), but apparently didn't plan on ever honoring my request (because, you know, I'm probably ignorant and will only hurt myself if allowed to do what I want).
The lack of pointers comes from the fact that Java is a "managed" language, meaning that it deallocates its own buffers, relieving you of the obligation to do so. I have written thousands and thousands of lines of C code, and can confirm that pointer and buffer issues can be difficult to solve. Having Java mop that stuff up for me is nice. Until it's not, which it isn't when you need to work directly on a lot of data (like in an image).
In sum: I agree with the others here who say Java's limitations are felt when you need unsigned native types, want to do pointer arithmetic, or work directly with hardware. Most of those limitations can be overcome with the JNI, though that just means that maybe
you should be working in another language to begin with. If those things don't impede you, Java is a great language. It's free, there are a lot of good IDEs that are also free, the library is fulsome and amazing, there is a vibrant community of users who will help you, and it is the most popular language of our era. If you are sloppy with pointers and buffers, Java will save you from yourself, most of the time. It's support for multi-threaded code is (particularly as of Java 8) mature and fairly easy to use.
What kind of stuff are you doing?