Say you’re writing method foo() in class A. foo doesn’t ever access any of A’s state. You know nothing else about what foo does, or how it behaves. It could do anything.
Should foo always be static, regardless of any other considerations? Why not?
It seems my classes are always accumulating many private helper methods, as I break tasks down and apply the only-write-it-once principle. Most of these don’t rely on the object’s state, but would never be useful outside of the class’s own methods. Should they be static by default? Is it wrong to end up with a large number of internal static methods?
To answer the question on the title, in general, Java methods should not be static by default. Java is an object-oriented language.
However, what you talk about is a bit different. You talk specifically of helper methods.
In the case of helper methods that just take values as parameters and return a value, without accessing state, they should be static. Private and static. Let me emphasize it:
1. Major advantage: the code is more expressive.
Making those methods static has at least a major advantage: you make it totally explicit in the code that the method does not need to know any instance state.
The code speaks for itself. Things become more obvious for other people that will read your code, and even for you in some point in the future.
2. Another advantage: the code can be simpler to reason about.
If you make sure the method does not depend on external or global state, then it is a pure function, ie, a function in the mathematical sense: for the same input, you can be certain to obtain always the same output.
3. Optimization advantages
If the method is static and is a pure function, then in some cases it could be memoized to obtain some performance gains (in change of using more memory).
4. Bytecode-level differences
At the bytecode level, if you declare the helper method as an instance method or as a static method, you obtain two completely different things.
To help make this section easier to understand, let’s use an example:
The lines we are interested in are the calls to
helper(...)on the classesWithoutStaticMethodsandWithStaticMethods.Without static methods
In the first case, without static methods, when you call the helper method the JVM needs to push the reference to the instance to pass it to
invokespecial. Take a look at the code of thecalculate()method:The instruction at 0 (or 1),
aload_0, will load the reference to the instance on the stack, and it will be consumed later byinvokespecial. This instruction will put that value as the first parameter of thehelper(...)function, and it is never used, as we can see here:See there’s no
iload_0? It has been loaded unnecessarily.With static methods
Now, if you declare the helper method, static, then the
calculate()method will look like:The differences are:
aload_0instructioninvokestaticWell, the code of the helper function is also a little bit different: there’s no
thisas the first parameter, so the parameters are actually at positions 0 and 1, as we can see here:Conclusion
From the code design angle, it makes much more sense to declare the helper method static: the code speaks for itself, it contains more useful information. It states that it does not need instance state to work.
At the bytecode level, it is much more clear what is happening, and there’s no useless code (that, although I believe the JIT has no way to optimize it, would not incur a significant performance cost).