Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When NOT to use the static keyword in Java?

People also ask

When should I not use static?

Static methods can't be used for abstraction and inheritance. You can't declare a static method in an interface or static abstract method in an abstract class. A static method cannot access non-static class level members, not its own, nor its base class.

Why should we avoid static in Java?

Static variables are generally considered bad because they represent global state and are therefore much more difficult to reason about. In particular, they break the assumptions of object-oriented programming.

When should we use static in Java?

In Java, static keyword is mainly used for memory management. It can be used with variables, methods, blocks and nested classes. It is a keyword which is used to share the same variable or method of a given class. Basically, static is used for a constant variable or a method that is same for every instance of a class.

Why You Should Avoid static classes?

Static classes have several limitations compared to non-static ones: A static class cannot be inherited from another class. A static class cannot be a base class for another static or non-static class. Static classes do not support virtual methods.


Two of the greatest evils you will ever encounter in large-scale Java applications are

  • Static methods, except those that are pure functions*
  • Mutable static fields

These ruin the modularity, extensibility and testability of your code to a degree that I realize I cannot possibly hope to convince you of in this limited time and space.

*A "pure function" is any method which does not modify any state and whose result depends on nothing but the parameters provided to it. So, for example, any function that performs I/O (directly or indirectly) is not a pure function, but Math.sqrt(), of course, is.

More blahblah about pure functions (self-link) and why you want to stick to them.

I strongly encourage you to favor the "dependency injection" style of programming, possibly supported by a framework such as Spring or Guice (disclaimer: I am co-author of the latter). If you do this right, you will essentially never need mutable static state or non-pure static methods.


One reason why you may not want it to be static is to allow it to be overridden in a subclass. In other words, the behaviour may not depend on the data within the object, but on the exact type of the object. For example, you might have a general collection type, with an isReadOnly property which would return false in always-mutable collections, true in always-immutable collections, and depend on instance variables in others.

However, this is quite rare in my experience - and should usually be explicitly specified for clarity. Normally I'd make a method which doesn't depend on any object state static.


In general, I prefer instance methods for the following reasons:

  1. static methods make testing hard because they can't be replaced,
  2. static methods are more procedural oriented.

In my opinion, static methods are OK for utility classes (like StringUtils) but I prefer to avoid using them as much as possible.


What you say is sort of true, but what happens when you want to override the behavior of that method in a derived class? If it's static, you can't do that.

As an example, consider the following DAO type class:

class CustomerDAO {
    public void CreateCustomer( Connection dbConn, Customer c ) {
       // Some implementation, created a prepared statement, inserts the customer record.
    }

    public Customer GetCustomerByID( Connection dbConn, int customerId ) {
       // Implementation
    }
}

Now, none of those methods require any "state". Everything they need is passed as parameters. So they COULD easily be static. Now the requirement comes along that you need to support a different database (lets say Oracle)

Since those methods are not static, you could just create a new DAO class:

class OracleCustomerDAO : CustomerDAO {
    public void CreateCustomer( Connection dbConn, Customer c ) {
        // Oracle specific implementation here.
    }

    public Customer GetCustomerByID( Connection dbConn, int customerId ) {
        // Oracle specific implementation here.
    }
}

This new class could now be used in place of the old one. If you are using dependancy injection, it might not even require a code change at all.

But if we had made those methods static, that would make things much more complicated as we can't simply override the static methods in a new class.


Static methods are usually written for two purposes. The first purpose is to have some sort of global utility method, similar to the sort of functionality found in java.util.Collections. These static methods are generally harmless. The second purpose is to control object instantiation and limit access to resources (such as database connections) via various design patterns such as singletons and factories. These can, if poorly implemented, result in problems.

For me, there are two downsides to using static methods:

  1. They make code less modular and harder to test / extend. Most answers already addressed this so I won't go into it any more.
  2. Static methods tend to result in some form of global state, which is frequently the cause of insidious bugs. This can occur in poorly written code that is written for the second purpose described above. Let me elaborate.

For example, consider a project that requires logging certain events to a database, and relies on the database connection for other state as well. Assume that normally, the database connection is initialized first, and then the logging framework is configured to write certain log events to the database. Now assume that the developers decide to move from a hand-written database framework to an existing database framework, such as hibernate.

However, this framework is likely to have its own logging configuration - and if it happens to be using the same logging framework as yours, then there is a good chance there will be various conflicts between the configurations. Suddenly, switching to a different database framework results in errors and failures in different parts of the system that are seemingly unrelated. The reason such failures can happen is because the logging configuration maintains global state accessed via static methods and variables, and various configuration properties can be overridden by different parts of the system.

To get away from these problems, developers should avoid storing any state via static methods and variables. Instead, they should build clean APIs that let the users manage and isolate state as needed. BerkeleyDB is a good example here, encapsulating state via an Environment object instead of via static calls.