Java is a compromise. It is result of the frustration with C++ and can be seen as a great simplification of this highly complex, multi-paradigm language. It is much harder to write a desastrous program (crashing a system) in Java than in C or C++.
Java checked exceptions are appealing at first sight, but soon turn out to lead to meaningless code mapping the checked exception of one API to the checked exception of another API, often accompanied by cascading stack traces in the resulting log files. Not surprisingly, the C# designers dropped this features.
Although the core language is relatively simple (probably with the exception of inner classes), some of the APIs are not, which may indicate that certain functionality is not easy to express in such a restricted language. It is interesting to observe, how Java is evolving. Partly driven by the evolution of C#, version 1.5 will introduce features such as generic types which were originally deemed too complex.
Considering, Java was designed as a new language from scratch, is not famous for the consistency of its API. As an example, the length of something is expressed in (at least) three different ways:
int n = "blah".length(); n = (new int[10]).length; n = (new ArrayList()).size();
The naming of classes and methods, however, is in general readable, since it avoids abbreviations. Unfortunately, the naming standard does not define how acronyms are written as part of identifiers. Are they all caps or just the first letter? The standard library demonstrates that people were still debating even when writing a single class (e.g., HttpURLConnection).