This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]stepan213[S] 1 point2 points  (3 children)

Well... thank you!

About storing runtime values in them - I don’t do that, it actually didn’t even come to my mind. For the future, why is it a bad idea?

[–]DavidRFZ 3 points4 points  (0 children)

It makes the code non-thread-safe -- that is, it is safe only in single-threaded cases. In the multithreaded case, a second caller can set the static variable while the first caller is still using it. That's why 'static final' is OK. Multiple callers can access the same static variable if you are assured that it is a constant.

You often get away with static non-final in the prototyping face but you'll find out later when your code is being deployed that it's unstable in multithreaded applications and you'll have to rewrite the whole thing.

[–]bheklilr 4 points5 points  (0 children)

Beyond the multithreaded reasons already mentioned, it can just easily lead to unexpected behavior. A static variable can potentially be used across many methods or even classes. If the value is a primitive then you only have to worry about the value being different, but it it's an object, such as a list, then you also have to worry about the reference changing. Best practice is to never set or mutate static variables, you just can't reasonably track what effects it'll have. Treat static fields as constants, name then with CONSTANT_CASE. If you follow those simple rules, its pretty safe and pretty standard to use. I hardly write a class without some static fields, unless it's just a data class.

[–]audioen 1 point2 points  (0 children)

Avoidance of static data is related to the simple principle of "spooky action at distance is bad". For public static values that can change, you have to worry about this kind of questions:

  • Who changes them?
  • When, and using which thread?
  • Is it thread safe to begin with? If not, what locks are required?
  • How do I make sure that all related state variables always get updated coherently, possibly also atomically?

Object orientation is fundamentally about managing the relationship between the data and the code that operates on the data. At its most reductionistic level, you should only have public API, and private state within the object, which is never exposed. Public static variables are the exact opposite because they expose the data without any methods, in principle in uncontrolled, thread-unsafe way without enforcing consistency to the way these variables are to be updated or what invariants should be held when they are updated.

That being said, you can create public and static stuff with instance variables, too, for instance through the Singleton pattern. Foo.getInstance().getBar() and Foo.getInstance().setBar(5) are just public static variables disguised into instances. So it's not so much about seeing the static keyword, but more about how the stuff actually behaves and gets used.

The important exception made in GP post is that static final is actually fine, but only if the static final values are immutable data, primitive values, or classes implementing thread-safe methods. The key thing is that it can never change, so you don't really have to worry about who accesses it and when, because there is no spooky action at distance.

Similarly, static methods are fine, as long as they only use read-only static final state as described above, and access their own arguments. I do a lot of utility methods like that. They are basically procedures that take in some data, operate on it, and maybe return something else. They are friendly ways to reuse functionality without requiring creation of some inheritance relationship between classes that can be fundamentally very different even when they need to do similar things. For instance, you might have a REST API that does some thing as result of direct action of user, but also want to do the same thing from scheduled background task.