简体   繁体   中英

When NOT to use the static keyword in Java?

When is it considered poor practice to use the static keyword in Java on method signatures? If a method performs a function based upon some arguments, and does not require access to fields that are not static, then wouldn't you always want these types of methods to be static?

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.

That's right. Indeed, you have to contort what might otherwise be a reasonable design (to have some functions not associated with a class) into Java terms. That's why you see catch-all classes such as FredsSwingUtils and YetAnotherIOUtils.

when you want to use a class member independently of any object of that class,it should be declared static.
If it is declared static it can be accessed without an existing instance of an object of the class. A static member is shared by all objects of that specific class.

An additional annoyance about static methods: there is no easy way to pass a reference to such a function around without creating a wrapper class around it. Eg - something like:

FunctorInterface f = new FunctorInterface() { public int calc( int x) { return MyClass.calc( x); } };

I hate this kind of java make-work. Maybe a later version of java will get delegates or a similar function pointer / procedural type mechanism?

A minor gripe, but one more thing to not like about gratuitous static functions, er, methods.

Two questions here 1) A static method that creates objects stays loaded in memory when it is accessed the first time? Isnt this (remaining loaded in memory) a drawback? 2) One of the advantages of using Java is its garbage collection feature - arent we ignoring this when we use static methods?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM