Clojure is a better Java than Java
A few weeks after starting with Clojure, I was talking to my friend John about how cool it was. John is one of those super practical "use the best tool for the job" types of engineers. I was talking excitedly and something just slipped out: "Clojure is a better Java than Java."
As soon as I said it, I knew it was the end of the conversation. It did not go well with him. Until then, the discussion had been basically which tool was better for the job, Clojure versus Java. But then I broke that completely and said that Clojure was better at Java's job than Java. This he could not take.
How is it possible that Clojure is better than Java at its own game? Bear with me. I have the time I didn't have with him to spell out everything. At the end, you can decide for yourself.
The basic operations of Java
One of Clojure's stated goals is to give you easy access to the underlying host platform. In practical terms, it means you can construct Java objects and call methods on them. But this is mostly what we do in Java---what I had been doing professionaly for years. I just want to show that Clojure can do what Java does, then we'll get into why it's better.
Construction in Java is done with the
new keyword. You type
new Object() and you have a new Object. Clojure lets you do that very
easily using the
new special form or more succinctly with a "dot
Both do the same thing.
Method calls in Java are done with a dot syntax:
Method calls in Clojure are done with the "dot prefix syntax".
(.push o 5)
You have the same prefix syntax as Clojure functions, but the dot means it's a method call.
Like I said, Clojure is not better just in this, only on par with Java. So in what ways is Clojure better?
The Java types
The Java type system is a static checker for the types of variables and arguments. It's supposed to catch bugs and make your code more robust. But is this really true? People complain all the time about how verbose the Java type system is. I mean, what about this kind of code:
List customers = new ArrayList();
Do I really have to say it twice? I make a list, what else could it be? And does it really make it safer that you had to say it twice? A lot of people (myself included) argue that the Java type system gets in the way more than it helps.
Clojure eliminates 99% of these type annotations. You give up the small amount of safety for a huge amount of flexibility.
Namespaces instead of classes
What do you do when you want to organize some Java code? You make a new class. You move the code in there, maybe as static methods, maybe regular methods. Then you get to call them from elsewhere.
But when you make a class, you're also making a new type. A new type just to organize some code? How do you know the class is meant to be instantiated instead of used for its code? Clojure gives you namespaces which are just for code organization and avoiding naming conflicts. Clojure makes it much clearer what the intent is.
Functions instead of classes
Another thing you see in Java is classes that have one method. Maybe
it's an instance of
or maybe it's an instance of a
You're supposed to make a new class (maybe an anonymous class) that
implements these interfaces. Then you instantiate them when you need
It has been said before that if you've got a class with one method, it's probably just a function. Clojure gives you functions for just this purpose. Again, Clojure is clearer with the intent, even though it doesn't have static types.
One thing that people really like about calling methods in Java is that they can chain. You can say:
It feels nice and convenient. And it usually is. But it has some downsides.
The object that
.b() returns has to have a
.c() method. Basically,
you're only able to chain as long as all of the classes have been
designed to do so. And many times, you're using someone else's library
and you can't modify classes. The standard answer is to wrap everything
in a Decorator. You
add a new class to your code for every class you need to wrap. Ugh!
The relevant chaining macro is called "thread first" in Clojure:
There's no savings there. But I can add calls to my own functions right in there, without relying on the designer of those classes to have thought of what I wanted to do.
(-> a ;; take object a
.b ;; call method .b
(call-my-function 10) ;; take the return and pass it to call-my-function
first ;; take the first of whatever that returns
str) ;; convert what that returns into a string
It's the best of both worlds. Things read top-to-bottom like a list of steps and you can mix methods and functions.
Clojure has the
doto macro. It directly replaces the typical Java
"configuration" pattern. You
create an object then set a bunch of properties on it.
Thread t = new Thread(runnable);
In Clojure, this becomes:
(doto (Thread. runnable)
(.setName "My Thread")
If I do want to give it a name, I just have to do this:
(let [t (doto (Thread. runnable)
(.setName "My Thread")
Seqs instead of iterators
are great. They give you uniform access to a lot of different
collections. But they're not perfect.
They're stateful and they don't work with everything (String and
arrays, plus custom collection types---why
do Java libraries define their custom iterator types?). Clojure's
Seqs, on the other hand,
are totally compatible with
Iterators, they're not stateful, and they
work with most everything (Strings, arrays,
nil, and collections).
One of the worst mistakes Java made was to include
null as a
Any reference can be
null. Just try to call a method on
null and you
Nil punning is a common feature of Lisps. Typically, it
nil represents the empty list and boolean false. Because
typically you're not calling methods in Clojure, you're calling
functions, the problem of Null Pointers almost goes away. Clojure's
nil is actually an expected argument in so many functions, it just
seems to fall through more gracefully.
Just as a simple example to make my point, this is considered dangerous in Java:
Why? Because what if
null? Uh oh! You're supposed to
Clojure handles this just fine:
(if (= my-string "Hello")
I don't mean to bash on Java. I just wanted to make that small point that for the stuff Java is mostly made of, Clojure kind of smoothes over a lot of the difficult parts. It's not perfect, either. But I think it makes the Java parts of Clojure kind of pleasant.
You still have to understand how methods work and what classes you have in the standard library and all of that. If you are new to the JVM, you'll want to learn those things. You can buy the JVM Fundamentals for Clojure course, which goes over interop (object construction and method calls) as well as the more useful parts of the Java standard library. You can also get it (along with 37 hours of videos) as part of a membership to PurelyFunctional.tv.