The Complexity of Java
Java has a well-deserved reputation for complexity, but it did not start out this way. In the beginning, Java flourished in part because it was so much simpler to write programs in Java than in the alternatives, e.g., C++. Garbage collection, collection classes, simple database API, sane networking API, and a simplified threading model combined to make programming in Java delightful. But that was 1995! Ten years later, Java is a complex beast. Writing enterprise programs with J2EE is extremely difficult. Maybe that’s an intrinsic difficulty of enterprise programming, but J2EE is certainly part of the problem. Since Java is getting too complex, programmers are starting to take a look at other technologies, like Ruby. And the Java community is taking notice — see ONJava.com’s discussion on Ruby — and fighting back. Graham Hamilton wrote a recent column where he listed some of the steps the latest version of Java is taking to simplify programming. I like the new constructs, but I’m afraid it’s a little too late for Java. Maybe it’s time to start learning Ruby.
Part of the problem with Java is the programming language. Java is a type-safe language, which means that variables are guaranteed (mostly) to refer to an object of the expected type. Strongly-typed languages have a common dilemma. Consider, for example, a binary tree. It would be nice to write the code for a binary tree without worrying too much about the actual type of the nodes. Some languages, like C++, allow you to do this via multiple inheritance: A single class can inherit from both a base class and a binary-tree node class. Other languages, also like C++, give you templates. Java’s original approach follows Smalltalk’s, where all objects inherit from a single base class (java.lang.Object in Java), so a programmer can write a binary tree of Objects and insert anything into the tree. That works well for Smalltalk, because Smalltalk is not a strongly-typed language! In Java, however, this is a bit of a disaster. Programmers are forever having to write code like this:
Vector v = getWombats();
Enumeration e = v.elements();
while (e.hasMoreElements()) {
Wombat w = (Wombat) e.nextElement();
...
}
The cast from e.nextElement() to Wombat is unsafe. If some non-Wombat object makes it into the collection — and there is nothing that prevents this from happening — the code will give a runtime exception. This goes against the Java philosophy, so it is phenomenal that it stood as the Right Way to do things in Java for so long.
Recently Java provided generics, which ameliorate some of these problems. The code above can now be written as follows:
Vectorv = getWombats(); Enumeration e = v.elements(); while (e.hasMoreElements()) { Wombat w = e.nextElement(); ... }
This is much cleaner, of course. But it is still a little too complex. The Enumeration is a bit of overkill, just for the privilege of walking through all elements of the collection. Once more, the recent version of Java provides us with a cleaner alternative:
Vectorv = getWombats(); for (Wombat w : v) { ... }
This new language construct makes it much easier to iterate over a collection. Gone is the dreaded Enumeration!
The irony, of course, is that this new language construct is exactly what Perl programmers have been doing for over 10 years. Python programmers have this construct, too, as do Ruby programmers. Java is no longer the leader in programming language design, it is a follower, a slow follower at that.
Graham Hamilton’s article lists some other examples where new Java syntax or libraries simplify code. These include opening a file (which was ridiculously hard in earlier versions of Java, to the point that I always had to look up the proper way to open a file, which I need to do in just about any program), registering JDBC drivers, accessing the default content pane, and locating resources in J2EE. In all of these, the new Java syntax is much better than the previous one. But the question is, why did take so long? It has been ten years, and other languages have given us simpler alternatives. Why did it take so long? And why are there still many, many unnecessary complexities left in Java?
The answer, I think, is Java’s culture. James Turner, Senior Editor of LinuxWorld Magazine, commented on the different cultures of Java and Perl, a comparison that makes Java look downright silly at times. Java programmers have fallen in love with patterns. I’m taking about the kind of love that is irrational, the kind that makes you blind. And while blindness in love may be a good thing when it happens between people, it is a disaster when it happens between a person and an idea. How else can you explain, for example, Java’s rampant use of the Decorator Pattern for file I/O? Thank goodness the latest version of Java is giving us a simple way to open files! Now if it could only make the other things as simple as, say, Ruby.