3

Which one is better?

public class A {
      private static final String DOSOMETHING_METRICS = "doSomethingmetrics";
      private static final String SAYSOMETHING_METRICS = "saySomethingmetrics";
      public void doSomething() {
            ...
            System.out.println("Metrics for " + DOSOMETHING_METRICS + "is something");
      }
      public void saySomething() {
            ...
            System.out.println("Metrics for " + SAYSOMETHING_METRICS + "is something");
      }
}

OR

public class A {
      public void doSomething() {
            final String DOSOMETHING_METRICS = "doSomethingmetrics";
            ...
            System.out.println("Metrics for " + DOSOMETHING_METRICS + "is something");
      }
      public void saySomething() {
            final String SAYSOMETHING_METRICS = "saySomethingmetrics";
            ...
            System.out.println("Metrics for " + SAYSOMETHING_METRICS + "is something");
      }
}

I think Method 1 wins in case of memory optimization as compiler allocated memory only once and the garbage collector doesn't need to deallocate the string created in every function call. However, I think good coding practice recommends that variable should be bound to the scope in which it has to be used and constants should be defined as close as to they first use in the program which is where Method 2 wins.

What is your take on this? Which aspect is more important? The functions here will be called multiple times (let's say at least 100K times).

Adi
  • 4,149
  • 4
  • 25
  • 41

2 Answers2

6

In both cases, these are constant variables as defined in JLS 4.12.4. So not only are the strings "doSomethingmetrics" and "saySomethingmetrics" interned, but so are "Metrics for doSomethingmetricsis something" and "Metrics for saySomethingmetricsis something". (Yeah, you need to add a space before "is".)

The first version logically has a slightly smaller stack, but I'd expect the JIT to optimize that away anyway.

I would use whichever form you find most readable. If you want to know for sure about the performance in your particular app, then as ever, the right thing to do is test both ways.

Looking at the results of javap -v, it looks like the second method actually has a slight advantage in that the unconcatenated strings don't even need to appear in the constant pool, as there's no way of reaching them. So you should see your class file being ever-so-slightly smaller that way. But again, I very much doubt that it'll make any difference.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you for your kind response. In case memory performance is same for both approaches, what is your take on coding style? – Adi Oct 12 '16 at 21:01
  • @Adi: Personally I prefer constants to be declared at the class level, but that's definitely a personal preference. – Jon Skeet Oct 12 '16 at 21:03
  • @Job: As per coding style goes, I prefer the second one, because I believe variables should not be available outside the scope of their desired life cycle. – Adi Oct 12 '16 at 21:05
  • @Adi: Well, it's not really a variable in the normal sense - you're really declaring a *constant*, and that doesn't have a life-cycle as such. But usually I agree with reducing scope as far as possible, and I certainly have no *problem* with the second style. – Jon Skeet Oct 12 '16 at 21:06
1

I think Method 1 wins in case of memory optimization

In both cases your string constants go to string pool and stored there. In second case you reallocate space for reference to your variable in stack frame. That's why I think that the first one is preferred one (but compiler can optimize the second case and they would be the same).

Community
  • 1
  • 1
Filipp Voronov
  • 4,077
  • 5
  • 25
  • 32
  • In case of Method 2, are the memory of the variables not cleaned up by the garbage collector when the function exits? To rephrase, when are string literals removed from the string pool? Are they kept there until JVM exit? – Adi Oct 12 '16 at 20:56
  • As far as I know string literals will continue to live, local variables (references to them) will be cleared from stack. – Filipp Voronov Oct 12 '16 at 20:57
  • @Adi: The value of the *variable* isn't a string - it's just a string *reference*. And no, the string won't be garbage collected as far as I'm aware. – Jon Skeet Oct 12 '16 at 20:57
  • @Philip: Thank you for telling me that. I just learned something new. However, this raises greater concerns for me. I am writing an application which reads records from a database sequentially in batches and processes them. If strings are not garbage collected until JVM exits, my memory footprint will keep increasing during the execution. Is there a good way to deal with it? – Adi Oct 12 '16 at 21:08
  • @Adi, it was about String **constants** that compiler places into String pool. Not all Strings stored there (for example that's why there is an [intern()](http://stackoverflow.com/questions/10578984/what-is-string-interning) method on String). – Filipp Voronov Oct 12 '16 at 21:15