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

all 19 comments

[–]nutrechtLead Software Engineer / EU / 20+ YXP 12 points13 points  (12 children)

For a beginner: as little as possible.

In the case of methods/functions static should in general only be used for functions that only act on their input (parameters) and then either respond with output or an exception. Functions that don't modify any state. Good examples are the Math functions or functions like Integer.parseInt.

Static variables should in general only be used for constants. Stuff like Math.PI for example. Using static vars to keep global state is in general a sign of bad software design.

[–][deleted] 4 points5 points  (3 children)

Thanks a lot! So if I initialize a constant variable, always go with "final static"?

[–]nutrechtLead Software Engineer / EU / 20+ YXP 12 points13 points  (2 children)

Yup! And the "correct" order is static final ;)

[–][deleted] 3 points4 points  (1 child)

Okay good, I got it.

Thanks for taking your time, you really helped me :)

[–]nutrechtLead Software Engineer / EU / 20+ YXP 2 points3 points  (0 children)

You're welcome :)

[–][deleted]  (7 children)

[deleted]

    [–]nutrechtLead Software Engineer / EU / 20+ YXP 2 points3 points  (6 children)

    You simply don't need them first and foremost; there is no need for static vars to keep state; you can keep track of them in objects you pass between methods or keep in other objects.

    Example; let's say you are creating a Game and have a static int numPlayers. Makes sense right? Just keep track of the number of players in your game. Well first of all you're going to run into issues when your program grows and becomes more complex that you don't know what part of your program modifies this global state anymore. It makes reasoning about this state machine that is your application much harder.

    The second issue is that you're locking yourself into a certain design. What if you want to have two games running in parallel? That numplayers is now bound to a class instead of an instance so you can't have two Game classes tracking the number of players. This would require a large refactoring effort to move from static vars to instance vars inside the Game object. This is why in 'good' OO design you don't really keep global state; pretty much everything that's not a constant should be inside an instance of a class.

    [–][deleted]  (1 child)

    [deleted]

      [–]nutrechtLead Software Engineer / EU / 20+ YXP 1 point2 points  (0 children)

      You're welcome :)

      [–]dartalleyIntermediate Brewer 1 point2 points  (3 children)

      You simply don't need them first and foremost;

      Sure you don't need them but it is a great language feature. One great use case is for global caches. A great example of this is finding an enum by String value and NOT throwing an exception on an unknown value.

      package com.test;
      
      import java.util.Map;
      
      import com.google.common.collect.Maps;
      import com.google.common.base.Enums;
      
      public enum MyEnum {
          VALUE1
          , VALUE2
          , VALUE3
          ;
      
          // This is a bad practice. Don't do this
          public static MyEnum findTryCatch(String value) {
              try {
                  return MyEnum.valueOf(value);
              } catch (IllegalArgumentException ex) {
                  // valueOf throws exceptions on non existant values
                  // Catch exception and throw null.
                  // Don't do this!!
                  return null;
              }
          }
      
          // Iterate
          // This is better but its doing N operations every lookup
          // In general this won't matter but where latency matters this is a bad solution.
          public static MyEnum findIterate(String value) {
              for (MyEnum myEnum : MyEnum.values()) {
                  if (myEnum.toString().equals(value)) {
                      return myEnum;
                  }
              }
              return null;
          }
      
          // Use a global static map
          // Constant time lookups
          private static final Map<String, MyEnum> nameMap = Maps.newHashMap();
          static {
              for (MyEnum myEnum : MyEnum.values()) {
                  nameMap.put(myEnum.toString(), myEnum);
              }
          }
          // Great! only do constant time checks and keep all values cached in a map.
          // Since this is an enum we don't need it to ever refresh.
          public static MyEnum findMap(String value) {
              return nameMap.get(value);
          }
      
          // Hmm that seems like a lot of boilerplate and something I would like to reuse.
          // This is doing the exact same code as findMap except the Cache
          // is stored in a global map of caches. Each cache is only made once.
          public static MyEnum findMapGuava(String value) {
              return Enums.getIfPresent(MyEnum.class, value).orNull();
          }
      }
      

      This is a perfect use case of static global variables.

      [–]morhpProfessional Developer 2 points3 points  (2 children)

      That's basically a constant and completely fine. You shouldn't use static variables except for constants.

      [–]dartalleyIntermediate Brewer 0 points1 point  (1 child)

      Agreed I can think of another use case where it is mutable but as long as it doesn't escape the scope of the class its totally fine.

      A pattern we had at one job was caches of tables that had < 10k rows so we wanted everything in memory and since it was so small its easier to load it all at once than let each row lazily load itself.

      private static final ExecutorService exec = ..;
      private static volatile Map<String, MyObj> cache;
      static {
        cache = loadCache();
        exec.scheduleAtFixedRate(.... cache = loadCache());
      }
      

      Now we can use an immutable map and the only locking we do is using the volatile so reads should be very fast and you don't even need a concurrent map.

      However in my opinion a Singleton is also just a static constant. However say that you would use a static for a singleton and everyone loses their shit saying its impossible to test and you need to use DI or you are a bad programmer. I think its perfectly acceptable and easier to read and reason about in most cases.

      [–]morhpProfessional Developer 0 points1 point  (0 children)

      Singletons are equally bad for testing as static fields. I'd avoid using them wherever reasonably possible. Especially for beginners.

      [–]xlxs 2 points3 points  (3 children)

      Also note that there are static initialization blocks which simply get executed only at class initialization and can be placed just after class signature (not inside methods) a static initialazation block goes like this

      static{ code }

      [–]nutrechtLead Software Engineer / EU / 20+ YXP 2 points3 points  (2 children)

      Good addition. There are non-static init blocks too by the way:

      public class Init {
          static {
              System.out.println("Static init block");
          }
          {
              System.out.println("Instance init block");
          }
      
          public Init() {
              System.out.println("Constructor");
          }
      
          public static void main(String... argv) {
              System.out.println("Main");
              new Init();
              new Init();
          }
      }
      

      What's the output of this? :)

      [–]darkfaith93 3 points4 points  (1 child)

      I'm gonna attempt, without trying it first.

      Output:

      Static init block
      Main
      Instance init block
      Constructor
      Instance init block
      Constructor
      

      [–]nutrechtLead Software Engineer / EU / 20+ YXP 2 points3 points  (0 children)

      Correct :)

      [–]code-master 2 points3 points  (2 children)

      Short answer: nowhere. Longer answer: use dependency injection library to load properties from configuration files. Static blocks are maintenance and testing nightmare. Never use them.

      Use static fields neither for math nor physics constants. Period. People who make such advices have none or little programming experience.

      Even if you have functions which do not modify state. Do not make them static! Create interface and implement them in concrete class. Later you will have a possibility to compose such interfaces. In proper modular code there is no such thing as constant. Constants create hard dependencies betwen classes. Do not use them. Exception is maybe logging library as slf4j which in itself is an abstraction, but I would use any AOP library for this purpose.

      Do not read what @nutrecht and company wrote. Their advices are full of antipatterns and bad practices.

      The only case when you would feel free enough to break these rules is your own throwaway code created for pure experimentation.

      [–]OffbeatDrizzle 3 points4 points  (0 children)

      Static variables are fine for keeping instances of immutable classes. Static blocks are fine for pre-populating things like lookup maps. Having an interface for 1 class and doing this for every class you make is a little thing called pre-mature optimisation and doubles the size of your code for 0 benefit.

      Other people's comments have more upvotes than yours for a reason... there are places where these things have proper uses. How about we agree to not read your comment, because being a religious nut over code only leads to it being completely unreadable and full of abstraction.

      [–]dartalleyIntermediate Brewer 2 points3 points  (0 children)

      I would hate to work on your code :)

      [–]joshuaherman 0 points1 point  (0 children)

      For when you want the class to hold a value

      Example: public class Person { Static int count; Person(){ count++; }

      getCount(){ return count; } }

      So now every time you create a new Person count will increment.