Java The Language Vs. Java the Platform
New and Noteworthy in JDK7 - Part 3
What’s perhaps a little more concerning is putting together tests for things that use AutoCloseable as collaborators. Previously, if something works with an InputStream, we would typically inject that (interface) directly into the class under test and have at it. We’re unable to do that when we “new up” the collaborator within a try-with-resources statement so we’re forced to pass in a factory. Not really a huge issue but it can lead to another indirect collaborator that you could argue obfuscates things. For example, the following won’t compile.
so, we’re forced to use a factory.
Which in turn means a typical test (in our case using jmock) is a little more verbose. I’ll leave it to you to decide if this could become a problem.
Dr Kabutz combined this new feature with a way to automatically unlock locked resources in a recent news letter. Here, the Java champion implements a basic unlock of a java.util.concurrent.Lock.
with the client calling something like
Although this is an interesting use of the new feature, developers have been getting around this kind of verbosity for a while by wrapping some anonymous instance of an interface or decorating classes with this kind of boiler plate repetition. An example I wrote for the tempus-fugit micro-library looks like this:
The “close” call is found in the familiar finally block. This is a good example of moving towards a lambda-like approach where clients would call some anonymous implementation like the following (making use of static imports for more syntactic sugar).
The reason I mention this alternative is to reflect on the more significant move to support lambdas that Oracle has put off. The tempus-fugit example is verbose because Java is verbose but with language support for lambdas, developers would be free to solve their own problems in a concise way. The tempus-fugit example is working within Java’s constraints, attempting to push aside the noise but with the introduction of lambdas proper, we wouldn’t need to. Introducing try-withresources is a response to the noise we usually put up with but it's focused on a very specific case. If instead, we saw lambda support, there just wouldn’t be such demand for things like this; we’d have all coded our way out of it already.
Catching Multiple Exceptions
This new feature allows you to catch multiple exceptions using a pipe to separate exception types. It removes the duplicated code you often get catching several exceptions and treating them in the same way. For example,
It looks like another workaround for the general gripes with Java; if you’ve got pages and pages of catch statements around a piece of code, it’s probably trying to tell you something. Exception handling is often contentious in Java. Forcing checked exceptions can often lead to the over use of the catch-and-re-throw anti-pattern and it takes a carefully considered approach to avoid the mess.
Some alternatives to leaning on the new syntax which may well lead to a better system, include decomposing the problem, identifying and separating roles and responsibilities and as a by-product isolating exception generating code. You could also try using lambda-like anonymous interface implementations or vanilla decoration to push off to the side the exception handling code (typically logging or wrapping works best here).
What’s probably more important than the mechanics though is identifying the real boundaries of your system; those places where you actually interact with system actors like the UI, frameworks or just the architectural “layers” of your system. Once you’ve spotted these, you can take steps to deal with exceptions at the appropriate place and answer the question of when to re-throw. The logical extension to this is to treat exceptions as sub-classes of RuntimeException and only catch and process them at your boundaries. Exclusively avoiding checked exceptions can reduce the clutter enormously but throwing runtime exceptions forces a high degree of responsibility onto the developer, something that is at odds with the typical “code defensively” development culture.
Given the example from Oracle above, I suspect this new feature will just facilitate ugly, jammed in code. It seems to say “it’s ok to deal with a bunch of exceptions in the same way. In fact, we’ll make it easier for you”. Typical to the Java world, there’s never a caveat around if you actually should be doing something, just an outline of how you could. The fact the example above (Oracle’s example, by the way) logs then re-throws is a smell in itself, something that developers around the world are likely to copy (it has the official Oracle stamp of approval after all). Perhaps I'm being too harsh, but I’m not a fan of this one.
There has also been a bunch of API additions in the JDK7 release, too many additions to mention here. A few notables however, include a new class Objects which offers helper methods to help with null safety and a trivial deep equals method. From the ever-popular concurrency package, there’s a new double-ended queue (Deque) implementation and a linked list based transfer queue. All in all though, I don’t imagine the average developer has been crying out for, or will relish, these minor additions.
I’ve certainly focused a lot on the language features and the JDK7 release is going to be more than just language features including updates to JDBC, NIO, and the new Sockets Direct Protocol for streaming over InfiniBand fabric on Solaris. I’ve also left out the details of some of the other new language features. We can look forward to more specificity on throwing exceptions, better support for dynamically typed languages running on the JVM (via the new invokedynamically byte code instruction), binary literals (0B10101010), underscores in numeric literals and the ability to use strings in switch statements.
Recent trends and the emergence of new JVM targeted languages has meant that Java has started to feel a little dated, a little long in the tooth. Amongst others, Scala is offering a less verbose, more elegant way to exercise our craft. The new language features of JDK7 are clearly aimed at addressing some of the communities’ frustrations with Java but just don't go far enough to repair Java’s fading reputation. We’re left on tenterhooks for JDK8 just like we’ve been on tenterhooks for JDK7 for this past two-dozen months.
With no major release of the Java platform for nearly five years, Oracle has a lot of lost time to make up for. Newer, more elegant and less verbose languages have emerged to meet the developer communities’ needs and most of them run on the JVM. As a platform, Java feels safe and secure, a warm place to curl up in. It’s a proven, hardened platform and new players are happy to build their futures on that premise. However, to compete as a language, Oracle would have to lurch Java’s language features forward like they did in 2004 with the release of Java 5, and the JDK7 release just isn’t it. Too much ground has been lost and Java’s fallen out of touch with the modern developer. Lambda support or reifiable generic types may have helped keep things fresh but I wonder if they’ll ever arrive and if so, whether we’ll have all moved on by then. The platform itself should also look forward. The lack of JVM support for infinite stacks or atomic multi-address updates (supporting STM) mean the platform can’t afford to sit on its laurels either.