First Impressions: Java

This is the first in a series of first impressions that I’m going to write each time I learn a new language or start using a new set of tools. I hope to keep track of what I thought and reexamine each in a few years. It will be interesting to see how my opinions change over time. This post is about Java. As I’ve been working in Python for the last few years, that colors my opinions about Java quite a bit.

Language

Forcing the programmer to catch every exception makes it very hard to quickly test various techniques or rapidly prototype a large amount of code. And there are cases where you know that a certain call will never raise an exception, even though it’s theoretically possible, but you still have to catch them. For example, I have to wrap this code in a try/catch block to catch java.net.MalformedURLException, even though I can look at the hard-coded URL and verify that it is well-formed:

URL url = new URL("http://www.example.com/");

And yet… you can still write a program that throws an exception. Shouldn’t that be impossible? If I write code that compiles, yet fails at runtime to catch an exception thrown by a method in a library, isn’t that a bug in the library, or the language? Doesn’t that mean that some low-level method is failing to catch, or declare that it throws, some exception?

Exception messages and stack traces are often missing critical information. Most simply say something like “invalid value” without including what the invalid value was, and without any hint as to what the range of valid values should be.

Having to declare types everywhere is a bit of a hassle. Here’s one example, at least, where types could just be determined implicitly:

FooBarThing fbt = new FooBarThing();

And yet, I still cannot make use of Java’s all-powerful type system to pass typed data into an applet from HTML. In other words, why can’t I use this HTML:

<applet code="foobar.class">
<param type="Integer" name="foo" value="77"/>
</applet>

to mean this:

Integer foo = getParameter("foo");

Instead, I have to convert all parameters from strings.

Having to buffer every file and network connection is pretty silly. The vast majority of the time, programs are dealing with files and sockets that don’t contain too much data to just read the whole thing into memory and manipulate it directly. And having to pass things through several chained buffers to do anything is just dumb.

The standard library tries to adhere to the CamelCase naming style, but does not always succeed. For instance, why is ‘zip‘ capitalized in java.utils.zip.GZIPInputBuffer, but not in java.utils.zip.ZipInputBuffer? Why is the ‘ttp‘ in ‘Http‘ lowercase in java.net.HttpURLConnection, but not the ‘URL‘? This kind of inconsistency makes it hard to remember, or find, items in the documentation when you mis-type them.

And what do all the acronyms mean? There’s the JRE and the JDK, plus J2EE, J2SE, J2ME, and JNLP. What are these, how are they different, which one do I need, and why should I care? I know big companies will pay more for “Enterprise” versions of software, but is all this fragmentation really necessary to the language? And I’ve figured out that Java 5 is Java 1.5, and Java 6 is Java 1.6, but does the language really need two version numbers? If I want to write an application in Python, I go to Python.org and download the current version of Python. I shouldn’t need to wade through marketing acronyms and figure out version numbers just to start writing in Java.

Documentation

Sun’s documentation is atrocious. Sun’s standard documentation pages use frames, making it hard to bookmark particular API pages. Googling for API components takes you to a child frame, which has no navigation links to get to the framed version or back to the API doc index. Finding documentation for the current Java version on Sun’s site is a combination of a billion clicks and URL hacking. Finding documentation for an older version is basically impossible, yet Googling often turns up an API documentation page for a long-outdated version, with no link to the current version. Compare this to how easy it is to find the documentation for the latest version of the language of a particular thing in Python.

Many of the tutorials start out with the most rudimentary explanations of general programming concepts. This makes the tutorial seem condescending to an experienced programmer who just wants to learn how to do X in Java. Then, the later parts of the tutorials are completely inaccessible to anyone without general Java programming experience, and since the Java libraries completely hide the basics that were explained in the beginning, the tutorials would seem weird and disconnected to a total novice. This is a classic middle-school writing mistake: writing without knowing who your audience is.

Part of the reason Python’s documentation is good is that it is an open-source, non-profit, community-focused project. If I see a typo on a Python doc page, or if someone wants to help reorganize the docs to make them easier to follow, their help is welcome. But am I going to help multi-million dollar Sun Microsystems improve their docs by suggesting an improvement or fixing a typo? No. And if I tried, would they listen? Probably not.

Compilation

What’s up with having to compile this anyway? Why can’t the browser just interpret and run the language? Unless you’re going for speed or memory efficiency, there’s no reason to use a compiled language these days. And Java’s not particularly fast or memory-efficient, even though it is compiled.

The gij and jikes compilers available on Ubuntu 7.10 get an immediate F, because neither could compile even the simplest hello world example copied off of the web. Sun’s compiler is the only one that seems to work.

Summary

Java makes the common tasks take as much code as the rare tasks. It seems that the designers of the language thought they were trading in the quick-and-dirty fuzziness of languages like Perl, PHP, or JavaScript, for the reliability and consistency of strongly-typed, pre-compiled languages like C and C++. I think this is a false trade-off. Python is reliable, orthogonal, and clean, like C, yet most common things can be accomplished quickly and simply with it, like Perl, or PHP.

The Java designers probably thought that forcing the developer to catch all exceptions would increase the reliability of the code. And it might improve reliability slightly. But just as with optimization or modularization, such extreme, constrained reliability is not necessary for every single piece of code. Python code can start off ignoring exceptions and evolve error handling over time. And quick-and-dirty Python code, where complete and utter failure is a non-issue, can punt on error handling completely. So the forced error handling is a false trade-off too.

I now know enough about Java to take it off of my “things I’d like to learn” list. I don’t want to write anything else in it. I can’t imagine a desktop, web, or server app for which Java would seem the best language to use. I wouldn’t take a job writing it, and I wouldn’t recommend it as a first language to learn.