GUI: the look and feel of the Graphical User Interfaces written in Java using Swing may not be the same as the widget look and feel of the underlying operating system. For example, on almost every Windows system, the Swing look & feel differ significantly from the GUI look and feel of the native applications. One possible solution is AWT, but it has its own limitations regarding the support of high-end widgets.
Floating point Arithmetic: Java largely supports IEEE 754 floating point arithmetic, but certain features are not supported even with the use of the ‘strictfp’ modifier in Java. For example, IEEE 754 recommends Exception Flags and Directed Roundings, but these features are not supported in Java.
Bytecode: while bytecodes make Java a portable language to a great extent, they cause the performance to slow down to a certain extent as well. If you use Java Interpreter while running the bytecodes on a certain JVM, then it’s considerably slower than the usual native code execution on that platform as the process adds an extra phase of translation of the bytecode instruction into the corresponding native code instruction. If we use JIT compiler to convert entire bytecodes into native code during load time or runtime, then also it incurs an initial penalty for the completion of the compilation. So, JIT compilation may be inconvenient especially for those applications which are either short-lived or which contain large amount of code. In the first case, the penalty will be too frequent while in the latter case, the penalty will be one time only, but this initial penalty will be huge :-)
Automatic memory management: Java uses the automatic garbage collector to handle all the memory management and the programmer has no control on it. Even, the execution of the garbage collection can not be controlled by the programmer. System.gc() will only result in a possible increment of the priority of the next garbage collection execution and that too is dependent on the particular J2EE implementation as the specification mandates nothing regarding this. If you deliberately want to free some important system resources like DB Connection, File Handles, etc. then you’re helpless and you got to rely on the sporadic execution of the garbage collection to do that for you. If you have enough system resources then you may not mind this, but in a crunch situation you’ll certainly not appreciate this limited/no control on memory management.
Different JVM for different platform: this is what makes Java a portable language, which is undoubtedly one of the major reasons for the popularity of Java, but it has its own share of limitations as well. Most of the implementations usually follow all the specifications, but they add certain implementation-specific flavors as well. If you somehow use any of those features then you compromise with the portability of your code. Even worse, your implementation may not be up-to-date with the latest specifications as well and this will cause compatibilities issues for the code written on an updated implementation. Having an implementation lagging in years with other popular implementations is not that bizarre either :-)
Being too strict may bother you: Java, being a strictly type-safe language, may pose certain problems to your comfort level with other languages which are comparatively generous. Automatic bounds checking for arrays, automatic virtual function indirection, run-time type checking, etc. may add little more inconvenience especially when you’re trying to prototype sample applications/modules/programs just to check certain functionality or maybe just to try and find few solution approaches to choose the best from. Extensive exception handling (usually a boon for the developers) will require you to write many lines of extra code for the successful compilation of the program. This may bother you while writing test-code/prototype.
Read more - Why Java doesn't have Clear Screen functionality? This article tries to explain why we can't have such functionalities in Java. It covers Java 6 updates as well.