My “Two Main Problems With Java” Rant

This is not an Anti-Java rant  Per Se.  It is a rant about the two main things missing from the language that force people into code heavy work-arounds.

Java has two flaws that hurt programmers using the language.  The first is that the reflection API does not provide the parameter names for a function.  The second is that Java allows null pointers.  This article explains why these two flaws are the impetus for many of the workarounds that require a lot of coding to do simple things.  This added complexity in turn leads to code that is harder to maintain and less performant.

An object in Java does not have any of the features of many true “Object Oriented” programming languages.  You can’t add properties or methods to an object after it has been created.  You need another abstraction for that kind of stuff: the map.  But Java provides introspection of the objects that make them map like.  An Object in Java is the “realization” of a Class, which is a set of rules.  The class exists to allow the programmer to define new rules about what a set of objects will do.  The idea is that the Class is the primary abstraction available to the programmer.  An Object has pre-conditions and post-conditions for any operations:  this will be true before and after this method is called.  These invariants are enforced by the Class of the Object.

This is the theory.  In practice, most Java classes violate this.  Java has one part of the problem built in to the language design of Garbage collection.  In C++ it is pretty common for an object to represent a resource.  Create the object, allocate the resource.  Free the object, release the resource. But garbage collection comes with a price:  you don’t know when your objects are freed, which means you can’t tie your resources to their object lifespans.  This is unfortunate, but it is a limitation of the language with which I can live.

However, just because we can’t tie clean up with resource release doesn’t mean we should allocate invalid objects.  However, this is done all over the place.  Lets look at the dependency injection model called setter injection.  Create an object, using the null constructor, and then call set, set ,set, and when you are done, you have an initialized object.  Note that type 1, or interface injection, is really just a more type safe way to do the same thing. There is no way of telling what is the minimum amount of work we have to do to get a valid object.  Do we have to call set on all properties?  The language already has a mechanism for answering this question.  THat is what the constructor is supposed to do.  Type 3 injection, constructor injection, then, looks like it should be the default way to go.  Why is it then so underused?

Imagine a language that gave you map, but no way to use the key. You could enumerate through all of the values, check their types, do all sorts of cool things, but you couldn’t look up values from the key. Programmers would probably complain? Yet the introspection of parameters in a java.lang.reflect.Method is limited to Types, not the names themselves.  The same is true of a java.lang.reflect.Constructor object.  We can get a collection of types, even a collection of annotations, but not a simple collection of strings for the names.  even if we did, there would be no way to create match that value with the object passed in as the  parameter.

Assume that you want to create an object of type DatabaseConnection.  To create this, you need a user ID, a password, and a JDBC URL.  Three strings.  To those of you who use objects like this regularly, you’ll notice that I changed the order.  The JDBC API usually has it as URL, Uid Password.  If all you know is that your API takes three strings, what order do you put them in?  You have to read the API docs.  Which is really not that useful if we want to make this an automated process. Ideally, the names of the parameters in the constructor would tell us which is which.

Note that if we used a specific type for UID, Password, and URL, we would have a guaranteed solution:  match the types of the parameters with the types of the objects that fill the dependencies.  But as soon as you have two objects of the same type, or any amount of casting, the policy becomes non-deterministic.

C++ aside:  C++ suffers from this just as much as Java, but C++ doesn’t even pretend to provide as much run time introspection that the failure there is just as bad.  Interesting to note that in modern  compilers, C, and by extension, C++ has allowed named parameters for structures, which can be used for this type of introspection, albeit a very chatty and non-runtime type.  Any one that suggest trying to demangle C++ functions will quickly see that A) any solution is non-portable and B) you lose the parameter names anyway.

Java has one other critical failing.  Null pointers.  If Java required that all references had a valid object connected to it, most of the justification for the Bean API would fall away.  If we defaulted most properties to final, the majority of objects would be immutable, and a whole slew of concurrency exceptions would fall away.  We would then just have to deal with the cases that an property was supposed to always exist, but be mutable.  This is why we have classes in the first case, and so these types of classes would be more common:  Wrap a primitive, but provide additional rules about what values it can assume. Without Null pointers, there would be no need for the Bean API.

Note that it would be easy to simulate a null pointer using a collection, or even an iterator.  A Collection would be empty.  An iterator would throw an exception to indicate that there was no “next” object.  This kind of Null pointer exception would be the exception, not the rule.

These two rules:  “no null objects” and “parameter type info” would significantly reduce the quantity of code written in Java while increasing reliability and correctness.

3 thoughts on “My “Two Main Problems With Java” Rant

  1. Thanks for the interesting post, Adam. You should look into dynamic scripting languages. For example, javascript treats objects as if they were hashes.

    With regards to parameter names, one way around that is to turn all of your parameters into properties (i.e. fields with getters and setters).

    With regards to null pointers, there are plenty of DI frameworks for Java these days so the modern Java developer experience is somewhat mitigated by this issue.

  2. Heh…I have quite a bit of experience with other languages. You are missing the point here.
    the reason to use a compiled language is the enforcement of contracts provided by the compiler. Waiting until interpretation time lets bugs lie dormant. If you look at my approach to IofC in c++ you’ll get a better sense of what I’m looking for here.
    ideally, the introspection of parameters would happen at compile time, with dependency resolution delayed until link time. Note that scripting languages don’t have either of these.

    as far as null pointers Spring, Nano and the others don’t stop you from having null pointers. Type two di actually exacerbates the problem.
    I’m an my phone responding now, but I’ll put together am ore coherent response later. Thanks for posting.

  3. Glen, just realized it was you. That s the problem with trying to do a response on a cell phone web browser.

    The goal here is not too for more convetions down the programmers throats. T the bean API is bad enough, and I ‘m trying to get away from that kind of programming.

    Let’s say you have a class that represents a machine on the network. For simplicities sake, we’ll model it like this:

    class Machine{
    public final String hostname;
    public final MACAddress mac;
    public Machine(String hostname, String mac){
    this.hostname = hostname;
    this.mac = mac;
    }
    }
    This kind of definition has a few advantages. It is immutable. Due to the introspection api it will work either early or late bound. The problem is that if you want to populate this object at run time, say from a file or from a database table, there is no way to match the values from the source with the parameters. A scripting language might give me named parameters, but at the codt of thread safety, as I do not know of any scripting language that will let me create an immutable object. In the scripting languages I’ve worked with the properties of an object are both public and mutable. I know Python, Perl, and PHP all suffer from this.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.