38

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?

9 Answers 9

55

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.

Sign up to request clarification or add additional context in comments.

12 Comments

So you'd argue against doing any I/O within a static method even if it does nothing with the state of the object, it's a sealed class, and you're passing in the object on which to perform the IO as an argument? I'd agree it'll still not be pure, but I don't see how making it an instance method helps in this case.
(I'd agree with mutable static fields generally being a bad idea, mind you.)
On a side note, to everyone else: expressing disagreement with Kevin is like expressing disagreement with Eric Lippert. I'm feeling nervous, almost expecting to be hit over the head with a giant cluestick. Please be gentle, Kevin...
Uh oh, I don't know this Eric Lippert, so now I'm paranoid that he's some kind of asshole. :) Here's the deal with your hypothetical static method that does I/O: it's fine. Oh, but the code that calls it? That code is not fine. That code is difficult to test. Since it uncontrollably performs I/O, my test needs to make sure that the state of things external to my program is set up in a particular way. Now I'm dependent on that setup, and if I forget it, I might be okay anyway depending on what order my tests are run in, and if I forget to restore pristine state later... etc.
@Kevin: I agree that's a general problem with any non-pure function, but how does only performing I/O in instance methods help? For tests, I'd prefer to inject the streams/readers/writers/etc - but that's a different matter from the method being static or not. I suspect I'm missing a point somewhere.
|
38

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.

8 Comments

Static is not about accessing the member fields or not. It is about class semantics. If a method applies to instances of the class, it must not be static. In your case, it is your collection instance that is read-only, not the class itself, so the function must be non-static. Static is really about class methods, for factories or utility functions.
Please, leave me the time to actually type my comment ;-)
If it takes a while to leave the comment, it may be worth doing that before casting the downvote :) (But thanks for commenting.)
I'm not actually sure which bit of your comment actually disagrees with what I've said - it's just expressed in a different way. I still think that it's relatively rare for a method to apply to an instance of the class, but not depend on its state. The only thing that can leave is the precise type of the object, which is where inheritance and overriding comes in.
@Roboprog: In that case I'd approach the testing differently. I very rarely override a method in a concrete class for the sake of testing. I'll implement interfaces or derive from abstract classes, but not concrete ones. Obviously it depends on the exact scenario, but I don't agree with uncontrolled inheritance/overriding :)
|
24

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.

5 Comments

+1 especially for the testing mention. We're using JUnit, and overriding methods in mock objects is a requirement.
Regarding 2: OO is a tool, not a goal.
@erikkallen Agreed. But when I use a OO language, I like to use this tool.
"static methods are more procedural oriented (and thus less object oriented)" not sure whether i understand that. A static method is still connected to its class and must be qualified when called from outside its class or statically imported, and if it doesn't need access to non-static members, why grant it?
What I mean is this style of code: Foo.bar(...); Bar.foo(...); ... i.e. procedural programming. I removed the (and thus less object oriented) which seems to be confusing.
4

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.

1 Comment

+1, even stateless methods might belong to an instance, and be available for override.
1

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.

2 Comments

That's a very coherent argument against static state, but not against static methods in general. Most static methods I write only use their parameters. Admittedly I do tend to use static logger variables, which I agree has issues...
Right, that's what I was trying to outline in the first paragraph - static methods that don't alter any state outside of their parameters are usually fine, but static methods that manage state can be troublesome. So I guess as a quick rule of thumb for deciding when to write a static method, you should see if any state will be affected by the method.
0

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.

Comments

0

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.

Comments

0

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. E.g. - 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.

Comments

0

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?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.