Am I the only one that worries about the mixing of Java language primitives, JVM functionality and API? Perhaps worrying is a bit too strong, but compared with more rigidly structured languages such as C / C++, Java has made a few compromises.
Lets take a look at a few of examples of what I am talking about.:
1) An enum has a base class (note the word ‘class’) definition of
public abstract class Enum< E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable
So is it really is a class, as it extends Object? It is defined using the enum keyword (language primitive) and has lots non class like behaviours, such as being implicitly final, non overridable, and must have the enum elements declared as the first item in the declaration.
Yes it is a class, but one with exceptional behaviour that is enforced on a one off basis - just for enums. The comment in the java docs says it all “This is the common base class of all Java language enumeration types.”
We see Java providing an elegant enum implementation where the enum’s have a lot of the benefits of being a class, but are not entirely class like.
2) All exceptions in Java must derive from Throwable, but the JVM does not enforce handling of exceptions derived from RuntimeException in the same way as it does for all other Throwable derived classes.
I maintain that throw and catch are language constructs, and should be unaware of the API structure.
Contrast this, with the more abstract C++ where you can throw anything that is relevant to the exception you are processing. Yes you are generally throwing classes, but they do not have to have a specific base class to be properly handles. In many ways C++ has more logical and powerful exception handling, but it requires convention and discipline, rather than compiler enforcement. This can lead to situations where you can fail to catch some category of exception as it went against the convention or leads you to have to catch non specific exceptions using the catch(…) format. This, although is the equivalent of Java’s catch(Throwable t), it does not allow the simple investigation and common reporting of the exception.
So again, we see that Java pragmatically violates the purity language components in the interests of making the language as a whole more useable.
3) References.
The ultimate API / JVM crossover is in the handling of References. SoftReference’s are cleared by the garbage collector in response to memory demand, while WeakReference’s are cleared when there are no soft or hard references. (I would probably be removing PhantomReference’s altogether) It could have been elegantly designed to use a (soft/weak) modifier keyword of the form:
weak Widget w = new Widget();
However, as References are are classes, they can have constructors that can take a reference queue argument.
There is good justification for these examples of language syntax pollution, and it is some of what makes Java a very useable language. I have been writing some C++ recently for the first time in about 3 years, and I had forgotten quite how much easier Java is in comparison. Java allows you to spend a higher percentage of your time writing business logic rather than worrying about getting the constructs right.
Java just kinda works, but it sometimes violates my love of crispness, and makes me feel just a little uncomfortable.