开发者

Should Java methods be static by default?

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 obj开发者_C百科ect'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:

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


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.


Interesting question. In practical terms, I don't see the point in making class A's private helper methods static (unless they're related to a publicly-accessible static method in A, of course). You're not gaining anything -- by definition, any method that might need them already has an instance of A at its disposal. And since they're behind-the-scenes helper methods, there's nothing to say you (or another co-worker) won't eventually decide one of those stateless helpers might actually benefit from knowing the state, which could lead to a bit of a refactoring nuisance.

I don't think it's wrong to to end up with a large number of internal static methods, but I don't see what benefit you derive from them, either. I say default to non-static unless you have a good reason not to.


No. Never. Static methods should be an exception. OO is all about having Objects with behaviour which revolves around the object's state. Imho, ideally, there shouldn't be any (or very few) static methods, because everything unrelated to the object's state could (and to avoid leading the concept of an object ad absurdum, should) be placed in a plain old function at module level. Possible exception for factories because Complex.fromCartesian (to take a wikipedia example) reads so well.

Of course this (edit: Module-level functions) isn't possible in a single-paradigm OO language (edit: like Java) - that's why I'm such a devoted advocate of multi-paradigm language design, by the way. But even in a language exclusively OO, most methods will revolve around the object's state and therefore be nonstatic. That is, unless your design has nothing to do with OO - but in this case, you're using the wrong language.


I usually

Perform these steps in order, as needed:

a) I write some code in a member method, figure out that I can probably re-use some of this code and

Extract to non-static method

b) Now I'll see if this method needs access to state or if I can fit its needs into one or two parameters and a return statement. If the latter is the case:

Make method (private) static

c) If I then find that I can use this code in other classes of the same package I'll

Make method public and move Method to a package helper class with default visibility

E.g. In package com.mycompany.foo.bar.phleeem I would create be a class PhleeemHelper or PhleeemUtils with default visibility.

d) If I then realize that I need this functionality all over my application, I

Move the helper class to a dedicated utility package

e.g. com.mycompany.foo.utils.PhleeemUtils

Generally I like the concept of least possible visibility. Those who don't need my method shouldn't see it. That's why I start with private access, move to package access and only make things public when they are in a dedicated package.


Unless you pass in an object reference, a static method on an class enforces that the method itself cannot mutate the object because it lacks access to this. In that regard, the static modifier provides information to the programmer about the intention of the method, that of being side-effect free.

The anti-static purists may wish to remove those into a utility class which the anti-utility purists surely object to. But in reality, what does artificially moving those methods away from their only call site achieve, other than tight coupling to the new utility class.

A problem with blindly extracting common utility methods into their own classes is those utilities should really be treated as a new public API, even if it's only consumed by the original code. Few developers, when performing the refactoring, fail to consider this. Fast-forward to other devs using the crappy utility class. Later on somebody makes changes to the extension to suit themselves. If you're lucky a test or two breaks, but probably not.


I generally don't make them static but probably should. It's valuable as a hint to tell the next coder that this method CANT modify the state of your object, and it's valuable to give you a warning when you modify the method to access a member that you are changing the nature of the method.

Coding is all about communicating with the next coder--don't worry about making the code run, that's trivial. So to maximize communication I'd say that if you really need such a helper, making it static is a great idea. Making it private is critical too unless you are making a Math. like class.


Java conflates the concepts of module, namespace, adt, and class, as such to claim that some class-oriented OO-purity should prevent you from using a java class as a module, namespace, or adt is ridiculous.

Yes the methods should be static. Purely internal support methods should be private; helper methods protected; and utility functions should be public. Also, there is a world of difference between a static field, a static constant, and a public static method. The first is just another word for 'global variable'; and is almost always to be avoided, even mediation by accessor methods barely limits the damage. The second is treating the java class as a namespace for a symbolic constant, perfectly acceptable. The third is treating the java class as a module for a function, as a general rule side-effects should be avoided, or if necessary, limited to any parameters passed to the function. The use of static will help ensure that you don't inadvertently break this by accessing the object's members.

The other situation you will find static methods invaluable is when you are writing functional code in java. At this point most of the rules-of-thumb developed by OO-proponents go out the window. You will find yourself with classes full of static methods, and public static function constants bound to anonymous inner functors.

Ultimately java has very weak scoping constructs, conflating numerous concepts under the same 'class' and 'interface' syntax. You shouldn't so much 'default' to static, as feel free to use the facilities java offers to provide namespaces, ADT's, modules, etc as and when you feel the need for them.


I find it difficult to subscribe to those avoid-static-methods theories. They are there to promote a completely sanitary object-oriented model anti-septically cleansed of any deviation from object relationships. I don't see any way essential to be anti-septically pure in the practice object-orientedness.

Anyway, all of java.util.Arrays class are static. Numeric classes Integer, Boolean, String have static methods. Lots of static methods. All the static methods in those classes either convert to or from their respective class instances.

Since good old Gosling, et al, proved to be such useful role models of having static methods - there is no point avoiding them. I realise there are people who are perplexed enough to vote down my response. There are reasons and habits why many programmers love to convert as much of their members to static.

I once worked in an establishment where the project leader wanted us to make methods static as much as possible and finalize them. On the other hand, I am not that extreme. Like relational database schema design, it all depends on your data modelling strategy.

There should be a consistent reason why methods are made static. It does not hurt to follow the standard Java library pattern of when methods are made static.

The utmost importance is programming productivity and quality. In an adaptive and agile development environment, it is not only adapting the granularity of the project to respond effectively to requirements variation, but also adapting programming atmosphere like providing a conformable coding model to make best use of the programming skill set you have. At the end of the day (a project almost never ends), you want team members to be efficient and effective, not whether they avoided static methods or not.

Therefore, devise a programming model, whether you want MVP, injection, aspect-driven, level of static-avoidance/affinity, etc and know why you want them - not because some theoretical nut told you that your programming practice would violate oo principles. Remember, if you work in an industry it's always quality and profitability not theoretical purity.

Finally what is object-oriented? Object-orientation and data normalization are strategies to create an orthogonal information perspective. For example, in earlier days, IBM manuals were written to be very orthogonal. That is, if a piece of info is written somewhere in a page within those thousands of manuals, they avoid repeating that info. That is bad because you would be reading learning how to perform a certain task and frequently encounter concepts mentioned in other manuals and you would have to be familiar with the "data model" of the manuals to hunt those connecting pieces of info thro the thousands of manuals.

For the same reason, OS/2 failed to compete with Microsoft because IBM's concept of orthogonality was purely machine and data based and IBM was so proudly declaring their true object-orientedness vs Microsoft's false object-orientedness pandering to human perspective. They had forgotten we humans have our own respective varying orthogonal perspectives of information that do not conform to data and machine based orthogonality or even to each other.

If you are familiar with the topology of trees, you would realise that you could pick any leaf node and make it the root. Or even any node, if you don't mind having a multi-trunk tree. Everyone thinks his/her node is the root when in fact any could be the root. If you think your perspective of object-orientation is the canon, think again. More important is to minimise the number of nodes that are accepted as candidate roots.

There needs to be a compromise between effectiveness and efficiency. There is no point in having an efficient data or object model that can be hardly effectively used by fellow programmers.


If it does nothing with objects of this class, but actually belong to this class (I would consider moving it elsewhere), yes it should be static.


Don't use static if you can avoid it. It clashes with inheritance ( overriding ).

Also, not asked but slightly related, don't make utility methods public.

As for the rest, I agree with Matt b. If you have a load of potentially static methods, which don't use state, just put them in a private class, or possibly protected or package protected class.


It depends i.g. java.lang.Math has no method which isn't static. (You could do a static import to write cos() instead of Math.cos()) This shouldn't be overused but as some code that is intented to be called as a utility it would be acceptable. I.g Thread.currentThread()


A static method is used to identify a method (or variable for that matter) that does not have to do with the objects created from that class but the class itself. For instance, you need a variable to count the number of objects created. You would put something like: 'private static int instances = 0;' and then put something in the constructor for that class that increments 'instances' so you may keep count of it.


Do think hard before creating a static method, but there are times when they are a good solution.

Joshua Bloch in "Item 1: Consider Static Factory Methods Instead of Constructors" in Effective Java makes a very persuasive case that static methods can be very beneficial. He gives the java.util.Collections class's 32 static factory methods as an example.

In one case, I have a hierarchy of POJO classes whose instances can be automatically serialized into XML and JSON, then deserialized back into objects. I have static methods that use Java generics to do deserialization: fromXML(String xml) and fromJSON(String json). The type of POJO they return isn't known a priori, but is determined by the XML or JSON text. (I originally packaged these methods into a helper class, but it was semantically cleaner to move these static methods into the root POJO class.)

A couple of other examples:

  • Using a class as a namespace to group related methods (eg, java.lang.Math).
  • The method truly is a private class-specific helper method with no need to access instance variables (the case cited here). Just don't sneak a this-equivalent into its argument list!

But don't use statics unthinkingly or you run the danger of falling into a more disorganized and more procedural style of programming.


No, the use of statics should be quite niche.

In this case the OP is likely 'hiding' state in the parameters passed into the static method. The way the question is posed makes this non-obvious (foo() has no inputs or outputs), but I think in real world examples the things that should actually be part of the object's state would fall out quite quickly.

At the end of the day every call to obj.method(param) resolves to method(obj, param), but this goes on at a way lower level than we should be designing at.


If it's only ever used by methods in A and wouldn't have any use outside it, then it should be static (and, probably, be placed in a Helper Class. It doesn't have any use outside A now, but there's no guarantee it will never have. Otherwise, it shouldn't.

If it doesn't have anything to do with the state of A, it could be useful at other places...

Anyway, that doesn't make a good reason for Java methods to be static by default.

Talking about this last issue, they shouldn't be static by default, because having to write 'static' make people think before writing static methods. That's a good practice when you have heterogeneous teams (the ones where Java is most useful).


When you write a static method you should keep in mind that you'r gonna use it at use-site with static-import (make it look class free) and thus it should behave just like a function which doesn't something and may or may not return something and is isolated with the state of class it belongs to. So static methods should be a rare situation.

If you seem to be making a lot of helper methods, then consider using package-private instance methods instead of private ones. Less typing, less boilerplate since you can re-use them as a helper to other classes in the same package.


I think "private static" (edit: for methods) is kind of an oxymoron in Java. The main point of static methods in my mind is to provide access to functions outside of the context of object instances. In other words, they're practically only ever useful if they're public. If you're only calling a method from within the context of a single object instance, and that method is private, it makes no sense to make it static. (edit: but, it makes no practical difference).

In this sort of case, I usually try to make the methods abstract enough that they're useful in other contexts, and I make them public in a utility class. Look at it as writing supporting library code, and think hard about your api.


Most static methods are written because

  1. You break down a complex method into submethods, or
  2. You wish String (or Date, or...) had some functionality that it doesn't have

The first is not bad per se, but it's often a sign that you're missing objects. Instead of working with default types such as String or List, try inventing your own classes and move the static methods to those classes.

The second reason produces the always-popular StringUtil, DateUtil, FooUtil classes. These are problematic because you have no way to discover that they exist, so programmers often write duplicates of these utility methods. The solution, again, is to avoid using String and Date all the time. Start creating your own objects, perhaps by wrapping the original object. The static methods become non-static methods of the new object.


If foo() doesn't have anything to do with Object A then why is the method in there?

Static methods should still be relevant. If there isn't anything going on then why have you written a method that has no association with it?


If foo is private, it may be anything, static or not. But, most of the time it will be not static as these is one less word to type. Then, if you need to use the state because you've changed your code, you can do it right away.

When it is protected or public, it depends on what it does. A rule of thumb is to make it not static when it isn't a part of the instance's behaviour, and make it static when it makes sense to call it without any object. If you are unsure, ask yourself if it makes sense to override the method in a subclass.


I think letting the methods in Java to be static will result in a rather chaotic implementation by beginner who haven't understand OO correctly. We've been there and think about it. If the methods were static as default how hard it is for us to understand the OO principle?

So yes, once you mastered the concept, it is a bit itchy to have static all over the methods (as result of refactoring). Nothing we ca do about that I think.

NB: Let me guess, are you by any chance have read Clean Code?


Plenty of interesting answers.

If you desperately seek a rule, then use this:

If the code is only ever used by instance methods of a single class, then make it an instance method - it is simply an extraction of code out of an instance context - which could be refactored back into (or out of) methods that access instance state.

If the code is used by MORE THAN ONE class, and contains no access to instance variables in the class in which the method resides, then make it static.

End of story.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜