; last updated - 6 minutes read

More often than not, the keyword static confuses Java programmers. As a consequence, Ken Fogel asks his students never to use static in Java unless explicitely told to do so. While that's a good hint for starters, it's only part of the story.

Funny thing is, I recommend to use static as often as possible. There's a twist: Never use static variables, but always use static methods.

Static variables

I suppose most readers of BeyondJava.net are fairly advanced Java programmers, so I'll cut the stories about static variables short: static variables are global variables, and global variables are a highway to hell. In a blink of an eye you're going to struggle with side effects. Things get worse in a multithreaded environment, such as Tomcat. Many Java programmers aren't really aware of it, so that's a point to stress: web applications use multithreading, so it's a real challenge to use static variables correctly. Just don't do it.

Static methods

Static methods are a different story altogether. They avoid trouble. Use static methods as often as possible.

That's because static methods can't access the object's attributes. Static methods aren't part of the object, so they don't have access to anything that belongs to the object. Instead, they belong to the underlying class of the object. Hence, static methods can only access static variables - and we've already declared them taboo.

The resulting effect is a functional programming style. Everything has to be passed as a parameter. That looks a bit cumbersome at first. After all, what are these nice objects for if we aren't allowed to modify their values? However, modifying the value of an object from within a method is a side effect. As long as you are aware of the side effect, everything is O.K., but when another programmer joins the team, they aren't aware of the side effect and runs into trouble. It may even happen to yourself when you return to the project after a year or two.

Static methods - also known as functions - are even more useful when it comes to multithreading. This time, the multi-user environment of your web server isn't the problem. But you should be very careful when you start to create new threads yourself.

Actually, the new parallel stream API of Java 8 actively discourages side effects. The stream API works with Lambda expressions, which in turn are functions which are allowed to access variables outside the scope of the function - but only if they are effectively final. That's not exactly the same as a static method, but it's close enough to achieve the same goal. It's difficult[1] to implement a Lambda causing side effects running havoc in a multithreading environment. Many people - including myself - complained about Java 8 Lambdas being less powerful than full-blown closures. Taking multithreading into mind, that design decision may turn out to be a live-saver. Or save you from working extra hours, for that matter.

The exception from the rule

Of course, students might make their methods static in order to be able to call them from the main methods. That's not what I'm striving at. Embracing the functional programming style doesn't mean you should get rid of objects. There's a good reason why we do object oriented programming. Granted, recently many voices consider object oriented programming dangerous, but as long as we're using Java, we should stick to object oriented programming. Classes and packages are like the index of a library: a good means to structure your code. Objects are tremendously useful, too. My point is to avoid side effects. Scala programmers can exploit final objects to achieve this goal (using val instead of var). In Java, that's not quite as simple. Favoring functions over methods helps to get rid of side effects.

Static classes

What about static classes? Well, I recommend to avoid them, but for a different reason. Do you know anybody who really knows what a static class is? I don't. Even if you do, does every member of your team know static classes? For some reasons, static classes are fairly exotic, so using them might confuse your co-workers.

Java knows only Static nested classes. You can't declare an arbitrary class static. It has to be an inner class. The meaning of static is a bit confusing: it means there's no reference to the surrounding object. This allows you to create an object of the inner class without having to create an instance of the outer class, and it may avoid memory leaks because the garbage collector can remove the outer class instances even if an inner class instance exists.

However, I prefer to keep things simple. Simply make the inner class an ordinary class. In any case, despite inner classes are very attractive in theory, I tend to avoid them in practice (with the sole exception of short anonymous inner classes - the majority of which are soon to be replaced by Lambda expressions). Among other reasons, files containing multiple classes tend to be very long. For the sake of clarity, I prefer to private or inner classes into a dedicated package.

Static initializers

Have you ever seen this construction?

public class Demo { static { System.out.println("The Demo class has been loaded."); } }

That's static, followed by a block of code. No, it's not a typo. Instead, it's tremendously useful. It's a static initializer. This piece of code is called when a class is loaded. In other words, it's called a single time during the life cycle of a class. Usually, classes are hardly ever removed from memory, so in most cases you can safely assume it is called only once (until the virtual machine is restarted).

The static initializer is called before the first instance of the class is constructed, so you can only access static variables and static methods. Static initializers are useful to populate caches that are shared among objects. This is one of the rare cases when you don't need to care about multithreading when you're writing or reading a static variable.

Since initializers are widely unknown, I'd like to introduce the non-static initializer to you, even if it's not today's topic.

public class Demo { { System.out.println("A Demo object is being created."); } }

This is a piece of code which is called when an object is constructed. It's similar to a constructor, except it can't take parameters. If a class contains both constructors and an initializer, the initializer is always called first.

Wrapping it up

The keyword static shows four different faces in the Java programming language. Cutting a long story short, I consider static variables dangerous, static methods useful and static classes sort of superfluous. Static initializers, in turn, are tremendously useful to populate caches and similar objects shared among objects and users.


Dig deeper

StackOverflow.com on static classes in Java

StackOverflow.com on static vs. inner classes in Java

Ken Fogel's video: Never use static in Java unless explicitely told to do so


  1. but not impossible↩

Comments