In this post I reiterate some well-known ways to shorten Java source code and to make it more readable.
Motivation for this is an observation that style is fun. Rethinking stylistic issues could help in dealing with complex problems. This is to provide for the future, while computation, after all, is not all about ownership.
##Index is structure
Creating complex structures, maps, or lists of objects, may be verbose or semi-fluent in Java. To forestall needless new code, big constructors, builders and whatnots, code should use built in data structures cleverly. One such pattern is a plain array and a loop over it, allowing the data itself be laid out pleasantly.
I have restricted the hard-to-read part of code to minimum, giving reader possibility to focus on the data and its internal relations. This will be useful especially when the amount of structural data within the program increases.
##Instance initialisers
A block, in a simple sense, means some lines of Java statements surrounded by { }.
An instance initialiser then is a block that is executed once per the lifetime of a java object.
Statements within the { } block are executed while an InIn is constructed, after the instantiation of the preceding list and before any constructor-methods. Notice how from reading this piece of code it is obvious what MyThing is parameterised with. The reader/maintainer does not have to remember a constructor signature to intuitively understand what happens, and we avoided creating two non-default constructors, those of InIn and MyThing.
Such an instance initialiser block does look a bit lonely, but then it could alleviate us from extensive constructor overloading or other contagious aesthetic maladies. This I’ll cover with another example later on.
However this pattern may lead to code deterioration in certain cases; keep in mind as always that a stylistic choice should lead to improved code clarity.
##Remove unnecessary getters
Getters may be required by frameworks like EJB and Spring, but otherwise they are seldom necessary. Especially getter-less data classes are more concise and more beautiful than getter-ified ones.
##Template data classing
In the above example we have a class that is used, say, in a traversable tree structure. The Node0 subclass then is static and therefore there is no extra complexity in its construction or garbage collection.
The field how, however, would be set twice, first to 1 and then to 0. Implicit superclass constructor always gets the first take. So we could omit variable initialisation in the super class. Depending on your JVM, your JIT could do this optimisation for you.
##… with a dynamic subclass (double brace initialisation)
If our object is constructed infrequently, we could use a dynamic subclass, along with a double brace initialisation pattern which is somewhat infamous. Beware of any implicit references that would prevent garbage collection of such an object, so mix this with builders or other inner classes only if you understand everything.
##Methods away
If we operate on data types that are not overtly specialised, it is extremely fast to accumulate common behaviors into helper methods, and using them will be a whiz. This is a philosophy behind Python, R, Matlab and other environments that were designed for scientific use: they offer easy access to computation, and undermine the notion and value of class structure per se. One interesting asset is that the simpler structures you use, the more portable your computations become. (Consider the Rootbeer project.)
Here are two examples in Java (a bad and a good one).
In Java 8, we could do without extractAge(), with a little lambda syntax and Java’s built in map/reduce facilities.
##Wielding asynchronous data classes
If you need to manipulate data from multiple threads, (a pattern that should be built on very sparingly), consider these options.
- AtomicReference and primitive datatype atomics there. These are classes for which atomicity of operations is guaranteed.
- on Java8, StampedLock for fast, advanced locking behaviors
The easiest way to prevent stale reads from memory, while these preceding options may or may not yield some performance benefits over it, is
Volatile dictates that your JVM will enforce the order of access to marked fields. In other words it is a bit like synchronized for fields in Java and ensures you will not read a stale value.
If you absolutely need to implement complex stateful behaviour that references an object, you should synchronise over the object itself in all client code, like this.
If we are uncertain of over what to synchronise, our program is likely to break, so it is good to keep to simple and thoroughly understood behaviours while we process data.
In finis, to summarise: it may pay to avoid any interfering idioms that boldly stand between a need and a clear solution. This post provided assorted ideas for that end. Resulting compact patterning will render Java an ok language. And while correctness and readability are necessary aspects of good code, fit and skinny structuring will assist us to get there.
As a bonus, here are some excellent background reads on Java: Josh Bloch’s Effective Java and Java puzzlers; Brian Goetz’ Java Concurrency in Practice.