Misfortunes of the Java Programming Language

I have a high opinion of Java as a general-purpose programming language. No language is perfect though. Here I will list some perceived flaws. Note: a language with just a handfull of flaws is a very good language.

In contrast to the basic Java language, the immense meandering Java libraries are very spotty. There are moments of brilliance, and better: moments of clear-headedness, but the moments one remembers are the nutty, stupid, and outright wrong ones.

Things missing in the language

const

The absence of a const modifier in Java results in making it very hard to control who is responsible for changing a given object. There is a workaround, but it’s messy and inefficient (see programmer’s FAQ).

I regard this lacuna as being the single worst flaw in Java, and because of it, I consider the language unsuitable for large projects, and say as much to clients and employers.

It is interesting that, programmers in languages such as C++ which have such a feature, use it everywhere, and consider it good programming practice, while Java programmers extremely rarely use the workaround that would give the equivalent control. Why would that be?

I think it is a matter of convenience. For example, while one could do something like object-oriented programming in C, the language really doesn't have the necessary syntactic features to facilitate inheritance. So nobody (in their right mind) really tries to do OOP in C, even if they think it is a good thing otherwise. Likewise Java programmers rarely try to control responsibility of altering data, because they have to stand on their heads to do so.

Another story: when I was a Fortran 77 programmer, I had no appreciation for structured programming. All I needed in life was arrays, and to me, the structures of Pascal and C were just a weird cute thing that no self-respecting programmer would touch. I'm all changed now. And now Fortran 90 has structures (but most of its users just use it for the improved comments and formatting). OK not such a good example.

the == operator means identical

The Java operator == means “identical”, not “equal”. For primitives, it is the same thing—for objects it is not.

Java variables are a hybrid of primitive and object, and one clear way to implement a common behavior for == is to say it means “identical”.

In C++ terms, the == operator performs pointer equality, rather than object equality. The Java developers were thinking in terms of pointers as references… there are other instances of this.

But unfortunately, and the symbol looks like “equals”, and the Java meaning is unlike our previous experience with == in other languages, so this choice has resulted in mistakes and confusion.

Besides, in applications programming, equality of variables is much a much more common question than identity. It would have been better to have had an operator such as

identicalto
and let == be overridable via the equals() method.

With Strings, this can result in very confusing behavior. Literal strings are instantiated at runtime as String objects. Many VMs will instantiate equal strings only once (as an optimization) so it will look as if == compares string equality. But that is not what’s happening. Two separate but equal string literals may be mapped at runtime to the same String object, so a comparison says they are identical.

The rule is: to see if Strings or other objects are equal, use the equals() method, not the == operator.

unsigned integer types

The standard objection to unsigned integer types is that in C, bad things happen when signed variables get cast as unsigned and vice-versa. Of course this is not an argument in the strongly-typed Java language.

I miss the counting numbers I had grown fond of in C++. To write tight Java code, I often have to write two check of integer arguments: is it too big, and is it too small.

In order to accommodate the loss of unsigned types, Java has an extra bitwise operator, the unsigned left shift >>>. If you mean your integers to represent a pattern of bits, the normal left shift does not do what you want: left shift by 1 does an arithmetic division by 2, which in the case of numbers with the minus bit set, is not the same thing. So: not only must we keep in mind our interpretation of the integers, but remember which shift operator to apply to them. Typically, only one ever makes sense. If both signed and unsigned integer types existed, the shift operator >> could have been made to do the right thing every time.

enums

I miss enum’s. Neat, efficient way to make a small integer type. (Java 5 now has enumerated types.)

multiple inheritance

Do we miss multiple inheritance? Maybe sometimes. Nah.

templates

It’s a drag to write a separate list class (and file) for each type of which one wants a list.

On the other hand, the C++ syntax for templates is horrid.

Could there have been a better way?

[Java 5 now has Generics. Have the shortcomings of C++ templates been overcome?]

Foul-ups with the language

crazed use of static

Particularly, that static variables are global across instances of applets. It would have been better to retain the traditional meaning of static, and invented a separate keyword (hey, how about global?) for this other behavior.

double meaning final

Has meaning of C++ const for variables, and C++ non-virtual for member functions.

Libraries

The Java libraries contain moments of brilliance, but what one comes away with is often a pretty disappointing experience. The style is almost as choppy as, say, X Windows (which was written over a longer period of time).

They really looks like the work of different groups with not very good agreement or common management. One would think a big company could do a better job.

Like many aging actresses, every very few years they undergo a face-lift, and at the same time become much larger and less manageable.

I find that I spend 90% of my time on any given Java project, trying to get around some poor library implementation.

Below is just a sampling of some of my experiences with them. It is in no way complete, even as a record of my experiences.

applet

Pity about applet not having setMenuBar in 1.1. Sure it’s a design faux pas sometimes, but the capability should have been there.

Why on earth does applet have AudioClip, but no means of generating a sound?

events

Don’t even talk to me about Java events.

I am aware of 4 implementations of event API's in the Java libraries (and depending on how you want to count them). The related function definitions, classes and interfaces are scattered across at least 4 packages. And with all that, it is still very hard for a programmer to write cross-platform code, say, to respond to a key stroke.

There is the original Component handleEvent (deprecated), then its replacements processEvent and the associated AWTEvents and EventListeners. Things got ever more complicated, but somehow, not closer to what I personally needed. In Swing, came KeyStroke and JComponent’s registerKeyboardAction. That wasn’t good enough, and is already deprecated. We are now to use getActionMap and getInputMap, which strike me as a lot more interface than I wanted. Sun seems to agree with this, as they have already deprecated part of that interface.

But in the end, one still cannot write simple, cross-platform code to do one thing when a certain keyboard key is held down, and something else when it is released.

Sun has been told of the problem dozens of times. They just deny it exists.

Could it really be that hard? It’s as if, every time a new SDK project head comes in, their first goal becomes to reform the events mechanism, and since it’s their first experience in reform, the botch it up. That would be consistent with the observations, at least.

awt

What function is really in charge of setting the various bounds of a Component? setLocation? the x, y one or the Point one? setBounds? setSize? This is really a problem if you want to override the default behavior of a component. There’s a similar problem with getBounds.

Graphics: The only functions that take a geometrical object are the Polygon functions. Shouldn’t all the geometrical drawing functions have taken geometrical objects as arguments? Sure would make for prettier code. Shouldn’t drawRect have taken a Rectangle argument? etc etc etc.

Point and Rectangle are sadly underdeveloped. Beside being under-used in Graphics, they lack many obvious functions.

Polygon is a disappointment. Shouldn’t it have taken an array of Point, instead of two arrays of int and another int to count them?

The sad, sad renaming of so many functions in 1.1.

The questionable default set of LayoutManagers. And shouldn’t the default LayoutManager for a component be one that doesn’t change anything? Why, yes. Instead, they all move and resize everything, including Buttons and such that shouldn’t be resized. The Java 2 solution is to make it all far more complex. It would have been better to start simple.

Popup Menus should have been in 1.1.

Absence of a selectable, inline text Component (as in a word processor, as opposed to a dialog text entry field)

Toolkit.getFontList deprecated in 2, moved to completely different class. Makes it difficult to write programs that depend on this that work in either environment.

Color: Why no toHTMLString() ? Why not a brighter( double amount )? Why no copy constructor? Why not a blend( Color, Color )? Why not parseColor( String, Color.StringFormat )?

Font: Why no copy constructor? Why a single integer style rather than separate style, weight, etc as in other font systems? Which comes first in Font constructor, style or size? (Would have been better if style were a type, rather than an integer).

Frame: setIconImage is so messed up. First, getting the icon in an applet can’t be done through the Toolkit, only by the Applet method. Second, setIconImage doesn’t work consistently across VM’s. Doesn’t work at all in IBM 1.3? I’ve heard that in MS VM, calling it for any Frame sets the icon in all frames (?). Third, Dialog isn’t a Frame, and doesn’t have setIconImage, although it does have a title bar. The consensus is that it should inherit its icon from the owner Frame passed to its constructor, but I’ve never seen it happen in a Linux VM.

Visibility vs size. Components don’t seem to get a size until they’re first made visible (or addNotify is called). This makes calculations on sizes of sub-components a terrible hassle.

lang

Classes representing a list and hash and stack should have been part of lang.

Why doesn’t Boolean have parseBoolean( String )? And hey, wouldn’t it have been nicer if all of
Integer.parseInt( String )
Long.parseLong( String )
Float.parseFloat( String )
Double.parseDouble( String )
were just named parse?

util

Tragically-named Vector class. Should have been a list or something. If someone wants to write an algebraic vector class, they have to call it something else. (I know, this is an old foul-up in computer science. But couldn’t some brave soul have stood up and objected? Maybe they did, and were taken out and shot.) Also, it’s so commonly used, it should have been in lang.