about:drewcsillag

Jan 24, 2015 - 9 minute read - programming java

Why Java?

Background

I started my professional career with a Pascal program (I know that dates me a bit) and then continued with C and C++ and discovered Python around version 1.4 and used it heavily for over ten years, and really didn’t like Java when I first met it (version 1.3-1.4 time frame).

I’ve also used a ton of other languages for real deployed projects, like Python, Ruby, C, C++, Common Lisp (which I <3 love), C#, Clojure, Visual Basic, and Go, so I’m a not the average “blub” programmer saying this.

But since about 13 years into my career, it’s become my tool of first choice for most things.

Manifest Typing

There are a lot of arguments for strong typing versus dynamic typing, but one thing I’ve not heard much about is the argument for manifest typing; that is, having the types of variables specified on declaration, or initial assignment. While it’s all well and good that the compiler can figure out what types things need to be, it’d be really nice if I, as a human, didn’t have to figure out what they were.

On this point, old me would kvetch and complain about how stupid it was, and that strong typing meant lots of typing whilst smugly waggling my fingers in a typing motion. Current day me, now having now read many code bases I didn’t write, in languages without manifest typing, have changed my mind on the subject. For example, what is the type of x?

x = self.db.getArtistRecord('artists', artistId)

The short answer is: without knowing what getArtistRecord returns, you don’t. Is it a dict, a tuple, some other object type? Now you need to find out where getArtistRecord is defined and look at it’s code to figure it out, and since db was probably passed into the current function, you now have to find the caller of the constructor of the current class to find that out… Then to understand what the eventual version of getArtistRecord returns (is it returned via a getattr hook?) you may have to again do this with the functions it calls. Lather, rinse, repeat. Compare to:

final ArtistRecord x = db.getArtistRecord("artists", artistId)

I know exactly what x is, without having to know the innards of db.getArtistRecord, no searching required, and even if I did, in Eclipse I can go right to the definition with Control-click, no muss, no fuss. If it’s an interface, I can view the class hierarchy with a single keypress.

This may sound trivial in your cases, but I’ve basically had to trace large chunks of a code base just to figure out what a simple function did. If your familiar with the code you work on, this doesn’t happen, but when you step into a largish code base you didn’t write, this is a significant barrier to being able to do anything. This coming from a guy that used Python heavily for over ten years. Compared to my experiences in stepping into large Java codebases whereby you could make minor changes fairly rapidly because it was easier to understand the function you need to deal with in isolation. This isn’t to say that you never have to traverse the code base to understand some chunks of code, but Java makes this so much easier, it’s not even comparable.

Tooling

Compared to languages like Python, Ruby, etc. The tooling of Java is just incredible.

Build System

Things like Maven as a build system allow for totally reproducible builds, and ways to mitigate versioning hell. You can be sure that what you built your code with is exactly the same as what your codevelopers are using. With Maven Central, you can just specify the library you want and it magically appears at build time. Want your own jar repository? No problem. With Maven’s archetypes, it can generate it’s own boilerplate. It auto-runs unit tests. The plug-in system allows for a ton of high-level automation like generating project files for Eclipse, or documentation generation, or deploying to Tomcat, or any number of other things. Is Maven a panacea? Of course not, anyone who’s had to dig into some weird error message will tell you so, but it’s really good at what it does.

JVM

The JVM is just a great piece of software. JVM with hotspot is incredibly performant. In one particular case, one of my teams translated a web service written in Python to Java in a straightforward way – that is, we didn’t do any algorithmic changes, just a straight port – and saw a 12x improvement, saving us much $$$ in machines and the management of those machines.

The fact that the JVM is cross-platform is also really great. My main development box is sadly a Windows 7 box. So I run Eclipse and Tomcat on Windows for development, and deploy to a Linux machine, and it all the tooling and code Just Works (TM). I just started migrating some services at work from Windows to Linux, and the Java stuff just worked. All the portability issues were about other things.

Threading? Sorry Python and Ruby (unless you use JRuby) you really lose here. Your GILs make things sad. They do work fine if you’re IO bound and you’re using it to multiplex without having to use something like Twisted.

Then there are a few “behind the scenes” kinds of things like the ever-improving memory management and garbage collection, the ability to have multiple class-loaders and the isolation you can have between multiple things running in the same JVM.

IDEs

I’m an Eclipse guy (I keep trying IntelliJ every few years, but it’s just not my thing, and never was able to get NetBeans to run on Linux), but what I’m going to say applies equally to at least IntelliJ and probably NetBeans. These tools are amazing in what they allow for. There’s the refactoring support that if you’ve never used before, are like anonymous functions – if you’ve never had them, you underestimate their value, once you have had them, you wonder how you ever got around without them. Eclipse’s quick-fix (Control-1) is probably my most used feature. For example, I want to make a list, what I do is:

myList = Lists.newArrayList(thing1, thing2);

Eclipse will helpfully underline myList in red squigglies because I didn’t specify the type. So I hit Control-1, and create local variable 'foo' is the first option, I hit enter and now I see:

List<ThingType> myList = Lists.newArrayList(thing1, thing2);

That menu contains a bunch of other options, like creating fields, changing foo (perhaps I mistyped it) and a bunch of other things, so my old “lots of typing” argument goes away. There’s functions to generate constructors based upon the object fields, creating getters and setters, and a zillion other things.

Then there’s the extensibility of Eclipse that allows for plugins to things like ZooKeeper, Spring, Git, Tomcat and more things you can shake a stick at.

Servlet Engines

I only have experience with Tomcat and Jetty, but both of these are extremely well done, and I expect that WebSphere and JBoss are similar. They’re high performance, and provide so much pre-baked functionality that if you’re doing a web service, unless you have very specific requirements that preclude them, you’d be a fool not to use one of them. They can handle the details of TLS, logging, configuration and management of DB connections, and so much more.

The Java Language and Environment

The Java language itself is ok. Not wonderful, but ok. I like Python, Ruby is ok. Rust looks very promising. I wish I could use Common Lisp or Clojure at work. I really want to like Go but the lack of generics and the way it deals with errors are really offputting to me, as are the distinctions between new and make. If Java had a macro system like Lisp’s that would be great – though annotation processors can get you part way there.

Annotation processors are really cool. Things like Lombok allows for annotation based code generation, as do things like Google Dagger 2 and the processing of these things is built into the JDK itself. They can also be used for auto-documentation generation and source code scanning like I did for generating documentation for JAX-RS web services.

Flat or shaded jars are also really nice. Think of it as a statically linked executable. They greatly simplify deployment as you can make running your application as simple as java -jar project.jar path.to.Main. Likewise, if you’re working with servlet engines, you can create a war files or ear which are self contained. Deployment is generally just well thought out.

Libraries

The selection of supported libraries for Java is just unmatched to just about any other language. The combination of a servlet engine, Jackson and Jersey make writing RESTful services, or just dealing with JSON, a breeze. There are tons of general utility libraries like Guava and apache-commons that have an extremely rich set of data types and threading utilties, among many other features. XML, YAML, or just about any other file format? You can bet there’s code to deal with it. Log4j just makes logging falling-off-a-log-(pun intended)-dead-stupid. JUnit and Mockito make unit and integration testing a breeze: if you add Docker and Helios, there’s the Helios testing framework which steps it up to whole other playing field. There’s JDBC which every notable SQL database has a supported client for, there’s Hibernate if you don’t like dealing with JDBC directly. There’s quality SOAP (yeah I know) support, and the list just goes on. Generally, if there’s a thing, there’s Java code to deal with it.

The fact that most JVM hosted languages like Clojure, Groovy, Scala, JavaScript (via Rhins or Nashorn), JRuby, Common Lisp (via ABCL) make these available to you, make the JVM a powerful integration point.

Java Is Not A Panacea

Java of course has it’s flaws. The JVM startup time isn’t wonderful, which makes it less ideal for command-line tools. It doesn’t support tail recursion, which while it’s not something you need often, is nice to have. It would make Clojure be able to get rid of (recur) which I’m really not a fan of. Type erasure in generics and that the generic parameters don’t survive to runtime stinks. The differences between int and Integer can be subtle and bite you unexpectedly. I also wouldn’t use Java as a browser plugin.

Java 1.8 finally got lambdas which are nice, as well as getting rid of the permanent generation which should save a number of production headaches.

Java ain’t perfect, and other languages have their place, but for doing production services, it’s a really good choice.