Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should Java methods be static by default?

Tags:

java

oop

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?

like image 650
Tom Tresansky Avatar asked Jul 27 '10 18:07

Tom Tresansky


People also ask

Are methods static by default in Java?

To answer the question on the title, in general, Java methods should not be static by default.

Should all methods be static in Java?

You should consider making a method static in Java : 1) If a method doesn't modify the state of the object, or not using any instance variables. 2) You want to call the method without creating an instance of that class.

Are methods static by default?

static method is a static member to the Interface, cant be overridden (as with the class), default method is the default implementation of a method which might be overridden.

Should I make all methods static?

If you're making all the methods static, then all the variables outside methods should be static as well. About threading, as per my knowledge, the difference would be when you would want to synchronize your code.


2 Answers

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:

Helper methods that do not access state should be static.


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:

public class App {     public static void main(String[] args) {         WithoutStaticMethods without = new WithoutStaticMethods();         without.setValue(1);         without.calculate();          WithStaticMethods with = new WithStaticMethods();         with.setValue(1);         with.calculate();     } }  class WithoutStaticMethods {      private int value;      private int helper(int a, int b) {         return a * b + 1;     }      public int getValue() {         return value;     }      public void setValue(int value) {         this.value = value;     }      public int calculate() {         return helper(value, 2 * value);     } }  class WithStaticMethods {      private int value;      private static int helper(int a, int b) {         return a * b + 1;     }      public int getValue() {         return value;     }      public void setValue(int value) {         this.value = value;     }      public int calculate() {         return helper(value, 2 * value);     } } 

The lines we are interested in are the calls to helper(...) on the classes WithoutStaticMethods and WithStaticMethods.

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 the calculate() method:

 0 aload_0  1 aload_0  2 getfield #2 <app/WithoutStaticMethods.value>  5 iconst_2  6 aload_0  7 getfield #2 <app/WithoutStaticMethods.value> 10 imul 11 invokespecial #3 <app/WithoutStaticMethods.helper> 14 ireturn 

The instruction at 0 (or 1), aload_0, will load the reference to the instance on the stack, and it will be consumed later by invokespecial. This instruction will put that value as the first parameter of the helper(...) function, and it is never used, as we can see here:

0 iload_1 1 iload_2 2 imul 3 iconst_1 4 iadd 5 ireturn 

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:

 0 aload_0  1 getfield #2 <app/WithStaticMethods.value>  4 iconst_2  5 aload_0  6 getfield #2 <app/WithStaticMethods.value>  9 imul 10 invokestatic #3 <app/WithStaticMethods.helper> 13 ireturn 

The differences are:

  • there's one less aload_0 instruction
  • the helper method is now called with invokestatic

Well, the code of the helper function is also a little bit different: there's no this as the first parameter, so the parameters are actually at positions 0 and 1, as we can see here:

0 iload_0 1 iload_1 2 imul 3 iconst_1 4 iadd 5 ireturn 

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).

like image 56
Bruno Reis Avatar answered Oct 06 '22 00:10

Bruno Reis


If a method does not use instance data, then it should be static. If the function is public, this will give the important efficiency boost that you don't need to create a superfluous instance of the object just to call the function. Probably more important is the self-documentation advantage: by declaring the function static, you telegraph to the reader that this function does not use instance data.

I don't understand the sentiment of many posters here that's there's something wrong with having static functions in a Java program. If a function is logically static, make it static. The Java library has many static functions. The Math class is pretty much filled with static functions.

If I need, say, a function to calculate a square root, the rational way to do it would be:

public class MathUtils {   public static float squareRoot(float x)   {     ... calculate square root of parameter x ...     return root;   } } 

Sure, you could make a "more OOPy" version that looked like this:

public class MathUtils {   private float x;   public MathUtils(float x)   {     this.x=x;   }   public float squareRoot()   {     ... calculate square root of this.x ...     return root;   } } 

But aside from meeting some abstract goal of using OOP whenever possible, how would this be any better? It takes more lines of code and it's less flexible.

(And yes, I now there's a square root function in the standard Math class. I was just using this as a convenient example.)

If the only place a static function is used and is every likely to be used is from within a certain class, then yes, make it a member of that class. If it makes no sense to call it from outside the class, make it private.

If a static function is logically associated with a class, but might reasonably be called from outside, then make it a public static. Like, Java's parseInt function is in the Integer class because it has to do with integers, so that was a rational place to put it.

On the other hand, it often happens that you're writing a class and you realize that you need some static function, but the function is not really tied to this class. This is just the first time you happened to realize you need it, but it might quite rationally be used by other classes that have nothing to do with what you're doing now. Like, to go back to the square root example, if you had a "Place" class that included latitude and longitude, and you wanted a function to calculate the distance between two places and you needed a square root as part of the calculation, (and pretending there was no square root function available in the standard library), it would make a lot of sense to create a separate square root function rather than embedding this in your larger logic. But it wouldn't really belong in your Place class. This would be a time to create a separate class for "math utilities" or some such.

You ask, "Should foo always be static, regardless of any other considerations?" I'd say "Almost, but not quite."

The only reason I can think of to make it not static would be if a subclass wants to override it.

I can't think of any other reasons, but I wouldn't rule out the possibility. I'm reluctant to say "never ever under any circumstances" because someone can usually come up with some special case.

like image 31
Jay Avatar answered Oct 06 '22 00:10

Jay