Java has WAY too many input readers, output writers, input streams, output streams, etc. I posted a list here: http://cboard.cprogramming.com/showthread.php?t=53763
Java does not allow overloading of operators. Being able to overload operators has always made things quite convenient. For example, in C++ you can simply overload the << and >> operators using ostream and istream to output or input any type of object you want. That is a heck of a lot better that using the trillion different types of readers, writers, input streams, and output streams that Java has.
Java has always been quite bulky when it comes to typecasting, and using primitive data types is always a nuisance when you want to put them into a list or tree of some sorts because you always have to create a new object. And then when you get them out of the data structure you have to typecast out of it and then get the value using something like intValue() or whatever. This specific problem is now solved with the new features being added in Java 2 1.5.0, but they should have been added a LONG time ago. C# has never had that problem.
Also, Java's String class is gimp and can do virutally nothing. There is a class (is it StringStream...or something of that nature) that is meant to give Strings more versatility, but even it does not measure up to the string class of C#, and BOTH C# and Java's string classes dont measure up to the STL string class of C++. The STL string class of C++ is the most versatile and powerful string class I have ever seen in my life.