-1

environment: JDK1.8 Windows 10

example1:

String msg=null;
for (int i=0;i<10;i++){
     msg="Hello";
 }

and example2:

for(int =0;i<10;i++){
      String msg = "hello";
}

Who can tell me the difference between these two examples and which code is more efficient

nanofarad
  • 40,330
  • 4
  • 86
  • 117
songzeyang
  • 31
  • 8
  • 1
    Both pieces of code will run essentially instantly. Depending on how smart the JVM is, the first can turn into a single action (loops 1-9 can be omitted), while the second can be removed altogether. (I'm not 100% sure on what the JVM will do here, which is why I'm posting this as a comment and not an answer.) Functionally, the difference is that only in the first snippet will `meg` be available after the loop (look up "variable scope" for more on that). As far as efficiency, my advice is that if you're doing something very fast (`meg = "hello"`) a small number of times, don't worry about it. – yshavit Aug 27 '18 at 04:22
  • 2
    @yshavit on the bytecode level, there is no notion of scope. So the only way, a JVM can eliminate the redundant operations, is to prove that there is no subsequent access to the variable. HotSpot can do this in either snippet, sometimes [better than a developer wishes](https://stackoverflow.com/q/26642153/2711488)… – Holger Aug 27 '18 at 11:03
  • @Holger That's not surprising, yeah. What I'm less sure of is how smart the JVM will be if you do use `msg` after the loop, in the first example (which is of course impossible in the second example). Will the JVM be smart enough to see that all of the calls do the same thing, and just invoke them only once? It wouldn't surprise me if they do recognize that, but I don't know, and I'm too lazy to experiment. ;-) – yshavit Aug 29 '18 at 06:06

1 Answers1

3

In the first example, msg is in-scope at the outermost scope shown, while msg is only in-scope in the loop body in the second example. Before I go on, I'll remind the reader that premature optimization, especially microoptimization as seen here, is not generally appropriate or useful and one should strive for clear, readable, and maintainable code above all.

I'll now continue for the curious reader. By compiling the code with javac 1.8.0_171 and disassembling with javap -c, I get the following bytecode:

First approach:

    Code:
       0: aconst_null
       1: astore_1
       2: iconst_0
       3: istore_2
       4: iload_2
       5: bipush        10
       7: if_icmpge     19
      10: ldc           #2                  // String f
      12: astore_1
      13: iinc          2, 1
      16: goto          4
      19: return

Second approach:

    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: bipush        10
       5: if_icmpge     17
       8: ldc           #2                  // String f
      10: astore_2
      11: iinc          1, 1
      14: goto          2
      17: return

As you can see, the two compiled outcomes are materially very similar. Both have a loop structure, and the body of the loop consists of load constant (ldc) followed by astore_<n> into a local variable slot. The assignment of variables to slots varies (first one assigns i to slot 2 and msg to 1, second does the opposite) but this should not have a significant effect. The first does include two extra bytecodes to store null to msg before the first iteration. However, the impact of this is so microscopic that it doesn't make sense to try to optimize this.

I don't currently have the toolset to view the resulting machine code from JIT optimizations, but I would strongly suspect that the entire loop would be optimized away by any capable JIT compiler.

nanofarad
  • 40,330
  • 4
  • 86
  • 117
  • 1
    In other words, the scope of the variable is entirely irrelevant (it isn’t even known at the bytecode level); all we see here, is the effect of the `null` assignment, which exists only in one version, and the order of occurrence. E.g., if we use `int i; String msg; for(i = 0; i < 10; i++) { msg="Hello"; }`, the scope changed for both variables, both now declared outside the loop, we get *exactly* the same bytecode as for the variant, where both variables where declared inside the loop. – Holger Aug 27 '18 at 11:13