Java… more of a standard than a piece of software, I guess, but let’s attack it anyway. The only question, as is often the case, is where to begin… and I’ll constrain myself by not even mentioning Swing (oops, too late).
First, there is the abysmal lack of support for real world file system handling. Like symbolic links, and unix permissions (Is this really coming in Java 7? about time).
Second, the incomplete support for asynchronous operations (any operation which blocks should be interruptible).
Third, and this one will be contentious, “equals” and “hashCode” should not be instance members. You should pass in a functor object which performs those operations to collection classes which need them (that’s not to say there might not be one or more default implementations of these functors).
Fourth, the collections library is incomplete. Why aren’t there utility classes such as JointSet (provides a set interface, backed by two or more real sets)?
Fifth, every object can be synchronized() on. Which means that every single object has a mutex hiding in it – which is a waste.
Sixth, it’s not possible to create a real Java sandbox from within a Java program, which is quite ironic seeing as this is really what Java was developed for (If you want to run some untrusted code, you can set a security manager, sure; but you can’t force a thread to stop running once you have started it. Even the deprecated Thread.stop() method won’t always work). There should be a safe way to stop threads (even if it means restricting what those threads can access/do), and you should really be able to intercept file and gui calls and handle them in any way you want (it shouldn’t just be limited to allowing or disallowing the operation).
Seventh, stupid version numbers. Java 5 – wtf? Java SE 6? Whoever came up with these names & numbers should be reprimanded!
Ah well, I guess that’s enough. For now anyway…