By Harry Joy


2012-01-10 13:01:15 8 Comments

Why does the following work fine?

String str;
while (condition) {
    str = calculateStr();
    .....
}

But this one is said to be dangerous/incorrect:

while (condition) {
    String str = calculateStr();
    .....
}

Is it necessary to declare variables outside the loop?

21 comments

@barrycarter 2019-09-09 17:48:22

This doesn't really answer your question ("why doesn't this work?"), but I wanted to disagree with @mike-nakis and say that block scoping is a bad idea.

Philosophically, for/while loops are part of the function they're written in, and shouldn't have their own, different variables. Functions and classes are clearly separate from each other, so function and class scoping are good ideas, but block scoping is not. Block scoping is a Java anomaly, although some other languages do it as well.

A more practical reason not to do it is that it's not portable. JavaScript doesn't have block scoping, and other languages may not as well. Quoting https://www.oreilly.com/library/view/javascript-the-definitive/0596000480/ch04s03.html

No Block Scope

Note that unlike C, C++, and Java, JavaScript does not have block-level scope. All variables declared in a function, no matter where they are declared, are defined throughout the function. In the following code, the variables i, j, and k all have the same scope: all three are defined throughout the body of the function. This would not be the case if the code were written in C, C++, or Java:

Since you don't gain anything from local scoping and since it's not portable, it's best to avoid using it at all.

Generally, your subroutines should be short enough that finding where a variable is declared should be easy. If you really need a separate scope inside a function, you're better off calling another function.

@Onur Günduru 2013-06-28 08:42:17

Please skip to the updated answer...

For those who care about performance take out the System.out and limit the loop to 1 byte. Using double (test 1/2) and using String (3/4) the elapsed times in milliseconds is given below with Windows 7 Professional 64 bit and JDK-1.7.0_21. Bytecodes (also given below for test1 and test2) are not the same. I was too lazy to test with mutable & relatively complex objects.

double

Test1 took: 2710 msecs

Test2 took: 2790 msecs

String (just replace double with string in the tests)

Test3 took: 1200 msecs

Test4 took: 3000 msecs

Compiling and getting bytecode

javac.exe LocalTest1.java

javap.exe -c LocalTest1 > LocalTest1.bc


public class LocalTest1 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        double test;
        for (double i = 0; i < 1000000000; i++) {
            test = i;
        }
        long finish = System.currentTimeMillis();
        System.out.println("Test1 Took: " + (finish - start) + " msecs");
    }

}

public class LocalTest2 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        for (double i = 0; i < 1000000000; i++) {
            double test = i;
        }
        long finish = System.currentTimeMillis();
        System.out.println("Test1 Took: " + (finish - start) + " msecs");
    }
}


Compiled from "LocalTest1.java"
public class LocalTest1 {
  public LocalTest1();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: dconst_0
       5: dstore        5
       7: dload         5
       9: ldc2_w        #3                  // double 1.0E9d
      12: dcmpg
      13: ifge          28
      16: dload         5
      18: dstore_3
      19: dload         5
      21: dconst_1
      22: dadd
      23: dstore        5
      25: goto          7
      28: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      31: lstore        5
      33: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      36: new           #6                  // class java/lang/StringBuilder
      39: dup
      40: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      43: ldc           #8                  // String Test1 Took:
      45: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      48: lload         5
      50: lload_1
      51: lsub
      52: invokevirtual #10                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      55: ldc           #11                 // String  msecs
      57: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      60: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      63: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      66: return
}


Compiled from "LocalTest2.java"
public class LocalTest2 {
  public LocalTest2();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: dconst_0
       5: dstore_3
       6: dload_3
       7: ldc2_w        #3                  // double 1.0E9d
      10: dcmpg
      11: ifge          24
      14: dload_3
      15: dstore        5
      17: dload_3
      18: dconst_1
      19: dadd
      20: dstore_3
      21: goto          6
      24: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      27: lstore_3
      28: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: new           #6                  // class java/lang/StringBuilder
      34: dup
      35: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      38: ldc           #8                  // String Test1 Took:
      40: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      43: lload_3
      44: lload_1
      45: lsub
      46: invokevirtual #10                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      49: ldc           #11                 // String  msecs
      51: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      54: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      57: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      60: return
}

UPDATED ANSWER

It's really not easy to compare performance with all the JVM optimizations. However, it is somewhat possible. Better test and detailed results in Google Caliper

  1. Some details on blog:Should you declare a variable inside a loop or before the loop?
  2. GitHub repository: https://github.com/gunduru/jvdt
  3. Test Results for double case and 100M loop (and yes all JVM details): https://microbenchmarks.appspot.com/runs/b1cef8d1-0e2c-4120-be61-a99faff625b4

DeclaredBefore 1,759.209 DeclaredInside 2,242.308

  • DeclaredBefore 1,759.209 ns
  • DeclaredInside 2,242.308 ns

Partial Test Code for double Declaration

This is not identical to the code above. If you just code a dummy loop JVM skips it, so at least you need to assign and return something. This is also recommended in Caliper documentation.

@Param int size; // Set automatically by framework, provided in the Main
/**
* Variable is declared inside the loop.
*
* @param reps
* @return
*/
public double timeDeclaredInside(int reps) {
    /* Dummy variable needed to workaround smart JVM */
    double dummy = 0;

    /* Test loop */
    for (double i = 0; i <= size; i++) {

        /* Declaration and assignment */
        double test = i;

        /* Dummy assignment to fake JVM */
        if(i == size) {
            dummy = test;
        }
    }
    return dummy;
}

/**
* Variable is declared before the loop.
*
* @param reps
* @return
*/
public double timeDeclaredBefore(int reps) {

    /* Dummy variable needed to workaround smart JVM */
    double dummy = 0;

    /* Actual test variable */
    double test = 0;

    /* Test loop */
    for (double i = 0; i <= size; i++) {

        /* Assignment */
        test = i;

        /* Not actually needed here, but we need consistent performance results */
        if(i == size) {
            dummy = test;
        }
    }
    return dummy;
}

Summary: declaredBefore indicates better performance -really tiny- and it's against the smallest scope principle. JVM should actually do this for you

@user207421 2014-07-01 04:16:42

Invalid testing methodology, and you don't provide any explanation of your results.

@Onur Günduru 2014-07-04 18:02:11

@EJP This should be pretty clear for those who have an interest in the subject. Methodology is taken from PrimosK's answer to provide more useful information. To be honest I have no idea how to improve this answer, maybe you can click edit and show us how to do it properly?

@Hardcoded 2015-01-02 16:17:09

1) Java Bytecode gets optimized (reordered, collapsed, etc) on runtime, so don't care about what is written at the .class files too much. 2) there are 1.000.000.000 runs to gain a performance win of 2.8s, so thats about 2.8ns per run vs. safe and proper programming style. A clear winner for me. 3) Since you provide no information about warmup, your timings are quite useless.

@Onur Günduru 2015-01-05 22:23:13

@Hardcoded better tests/micro benchmarking with caliper only for double and 100M loops. Results online, if you want other cases feel free to edit.

@Hardcoded 2015-01-08 09:46:45

Thanks, this elimiates point 1) and 3). But even if the time went up to ~ 5ns per cycle, this is still a time to be ignored. There's a small optimization potential in theory, in reality the stuff you are doing per cycle is usually a lot more expensive. So the potential would be a few seconds at maximum in a run of some minutes or even hours. There are other options with higher potential available (e.g. Fork/Join, parallel Streams) that I would check before spending time on this kind of low-level-optimizations.

@Onur Günduru 2015-01-08 10:20:30

@hardcoded yeah, don't get me wrong I'm not a fan of useless optimizations but if you need it, this is what you get. Actually such an optimization could even be possible in the JVM, however, that's another story...

@user207421 2015-07-06 20:22:02

@OnurGunduru That is a thoroughly futile comment. If I really had no 'interest in the subject' I would certainly not be commenting here. The fact that someone else used the same methodology doesn't make either of them valid. Circular argument. Your test code is liable to be optimized away entirely in either or both cases. It proves nothing. And you can't 'improve' an invalid result.

@Onur Günduru 2015-07-09 15:56:24

@EJP maybe you should take some time to understand how Calipher works or write another test case to prove yourself?

@Mike Nakis 2015-10-04 21:15:48

Not only you need to warm up, but also, you need to do multiple runs, record the standard deviation between all the runs, and see how the difference compares to the standard deviation. If the difference is close to the standard deviation, then you can be pretty sure that you are just looking at noise.

@Onur Günduru 2015-10-05 15:16:35

@MikeNakis Calipher takes care of these, code is in the github please feel free to play with it. One thing to remark is that you have to return something from the method, otherwise JVM will skip the assignment code... so you need to have a dummy return variable. BTW I don't say Calipher is perfect, it's aimed at microbenchmarking if you have better alternatives please share to find a reasonable baseline to this argument. Long story short, declaredBefore indicates better performance -really tiny- and it's against the smallest scope principle. JVM should actually do this for you

@Mike Nakis 2015-10-05 18:32:29

@OnurGunduru okay, I am sorry, I should have looked it up before commenting. Cool stuff. I still find it hard to understand why there is a difference, and even to believe that there is in fact a difference.

@Onur Günduru 2015-10-07 10:24:36

@MikeNakis thanks, I've also came across with java-performance.info/jmh might be worth to check out

@Onur Günduru 2017-04-18 10:50:16

@MikeNakis Looks like JMH will be the 'official' tool in Java9 for microbechmarking javax0.wordpress.com/2016/09/11/…

@Sanjit 2017-08-09 10:11:19

I think the size of the object matters as well. In one of my projects, we had declared and initialized a large two dimensional array that was making the application throw an out-of-memory exception. We moved the declaration out of the loop instead and cleared the array at the start of every iteration.

@Mike Nakis 2012-01-10 13:12:13

The scope of local variables should always be the smallest possible.

In your example I presume str is not used outside of the while loop, otherwise you would not be asking the question, because declaring it inside the while loop would not be an option, since it would not compile.

So, since str is not used outside the loop, the smallest possible scope for str is within the while loop.

So, the answer is emphatically that str absolutely ought to be declared within the while loop. No ifs, no ands, no buts.

The only case where this rule might be violated is if for some reason it is of vital importance that every clock cycle must be squeezed out of the code, in which case you might want to consider instantiating something in an outer scope and reusing it instead of re-instantiating it on every iteration of an inner scope. However, this does not apply to your example, due to the immutability of strings in java: a new instance of str will always be created in the beginning of your loop and it will have to be thrown away at the end of it, so there is no possibility to optimize there.

EDIT: (injecting my comment below in the answer)

In any case, the right way to do things is to write all your code properly, establish a performance requirement for your product, measure your final product against this requirement, and if it does not satisfy it, then go optimize things. And what usually ends up happening is that you find ways to provide some nice and formal algorithmic optimizations in just a couple of places which make our program meet its performance requirements instead of having to go all over your entire code base and tweak and hack things in order to squeeze clock cycles here and there.

@Harry Joy 2012-01-11 04:15:36

Query on last paragraph: If it was another then String which is not immutable then does it affect?

@Mike Nakis 2012-01-11 04:23:04

@HarryJoy Yes, of course, take for example StringBuilder, which is mutable. If you use a StringBuilder to build a new string in each iteration of the loop, then you could optimize things by allocating the StringBuilder outside the loop. But still, this is not an advisable practice. If you do it without a very good reason, it is a premature optimization.

@Mike Nakis 2012-01-11 04:23:35

@HarryJoy The right way to do things is to write all your code properly, establish a performance requirement for your product, measure your final product against this requirement, and if it does not satisfy it, then go optimize things. And you know what? You will usually be able to provide some nice and formal algorithmic optimizations in just a couple of places which will do the trick instead of having to go all over your entire code base and tweak and hack things in order to squeeze clock cycles here and there.

@Nirmal- thInk beYond 2012-01-11 04:37:07

I want to ask about cost of declaration (initialization cost will be same in both case), leave about string, think about object, when we are declaring object inside large loop so does it effect on performance at least little?

@Mike Nakis 2012-01-11 04:39:03

@Nirmal-thInkbeYond I just answered this using StringBuilder as an example. Read 3 comments above.

@Siten 2012-01-11 04:45:43

@MikeNakis i thing you are thinking in very narrow scope.

@Siten 2012-01-11 04:48:08

@MikeNakis What will be behaviour of method stack in both the cases? How many times the variable type is put into stack frame?

@Mike Nakis 2012-01-11 04:51:53

@Siten Variable types are not put into stack frames. Please carefully read the article at "livingtao.blogspot.com" that you linked to; it explains it quite well.

@Siten 2012-01-11 04:57:03

@MikeNakis my dear friend i read it very very carefully it said there is no way to declare it. so the main thing about the performance of executing loop.

@PrimosK 2012-01-16 10:01:32

@MikeNakis would you agree with the answer I provided or did I miss something?

@Mike Nakis 2012-01-16 10:33:57

@PrimosK No, you did not miss anything, you are right on the money. That's what the "livingtao" blog post linked by Siten's answer also found. What I am saying is that even if declaring the string inside the while loop was incurring some performance penalty, (which, as you have proved, it doesn't,) the best coding practice would still be to declare the string inside the loop, because that's the smallest possible scope for it.

@Mike Nakis 2012-01-16 10:36:40

You see, modern multi-gigahertz, multi-core, pipelined, multi-level-memory-cache CPUs allow us to focus on following best practices without having to worry about clock cycles. Furthermore, optimization is only advisable if and only if it has been determined that it is necessary, and when it is necessary, a couple of highly localized tweaks will usually achieve the desired performance, so there is no need to be littering all of our code with little hacks in the name of performance.

@Nick 2017-12-28 20:08:52

If you are writing functions so large that scoping a few loop variables is a major concern to you, then you have far greater problems than variable scoping.

@Phil Goetz 2018-04-12 04:07:01

1: In a language like Java, which is fast and has good garbage collection, maybe. In a language like Perl, which is slow and has terrible garbage collection, maybe not. 2: See Onur Gunduru's speed test below, which is a different case, but shows a big runtime win for declaring it inside the loop.

@Mike Nakis 2018-04-13 14:25:48

@PhilGoetz 1. This question is tagged with [java]. 2. A programmer's choice to use a scripting language instead of a real language automatically disqualifies them from participating in performance-related discussions.

@rt15 2014-11-21 15:41:31

Warning for almost everybody in this question: Here is sample code where inside the loop it can easily be 200 times slower on my computer with Java 7 (and the memory consumption is also slightly different). But it is about allocation and not only scope.

public class Test
{
    private final static int STUFF_SIZE = 512;
    private final static long LOOP = 10000000l;

    private static class Foo
    {
        private long[] bigStuff = new long[STUFF_SIZE];

        public Foo(long value)
        {
            setValue(value);
        }

        public void setValue(long value)
        {
            // Putting value in a random place.
            bigStuff[(int) (value % STUFF_SIZE)] = value;
        }

        public long getValue()
        {
            // Retrieving whatever value.
            return bigStuff[STUFF_SIZE / 2];
        }
    }

    public static long test1()
    {
        long total = 0;

        for (long i = 0; i < LOOP; i++)
        {
            Foo foo = new Foo(i);
            total += foo.getValue();
        }

        return total;
    }

    public static long test2()
    {
        long total = 0;

        Foo foo = new Foo(0);
        for (long i = 0; i < LOOP; i++)
        {
            foo.setValue(i);
            total += foo.getValue();
        }

        return total;
    }

    public static void main(String[] args)
    {
        long start;

        start = System.currentTimeMillis();
        test1();
        System.out.println(System.currentTimeMillis() - start);

        start = System.currentTimeMillis();
        test2();
        System.out.println(System.currentTimeMillis() - start);
    }
}

Conclusion: Depending of the size of the local variable, the difference can be huge, even with not so big variables.

Just to say that sometimes, outside or inside the loop DOES matter.

@Hardcoded 2015-01-02 16:26:31

Sure, the second is faster, but you are doing different stuff: test1 is creating a lot of Foo-Objects with big arrays, test2 isn't. test2 is reusing the same Foo object over and over again, which might be dangerous in multithreaded environments.

@rt15 2015-01-05 09:15:24

Dangerous in multithreaded environment??? Please explain why. We are talking about a local variable. It is created at each call of the method.

@Hardcoded 2015-01-08 08:41:58

If you pass down the Foo-Object to a operation that is processing the data asynchronously, the operation might still be working on the Foo-instance while you are changing the data in it. It doesn't even have to be multithreaded to have side-effects. So instance-reusing is quite dangerous, when you don't know who is still using the instance

@Hardcoded 2015-01-08 08:44:26

Ps: Your setValue Method should be bigStuff[(int) (value % STUFF_SIZE)] = value; (Try a value of 2147483649L)

@Hardcoded 2015-01-08 08:49:19

Speaking about sideeffects: Have you compared the results of your methods?

@rt15 2015-01-09 09:31:58

Yes there are side effects. My point is that sometimes, if you instantiate a big object (Even not so big: 512 longs...) in a loop, it is sometimes greatly faster to code differently and to reuse the same instance. Obviously, to be able to do that, the instance has to be reusable.

@Pavan 2012-01-23 06:06:43

As many people have pointed out,

String str;
while(condition){
    str = calculateStr();
    .....
}

is NOT better than this:

while(condition){
    String str = calculateStr();
    .....
}

So don't declare variables outside their scopes if you are not reusing it...

@Dainius Kreivys 2014-03-07 09:21:25

except probably in this way: link

@olyanren 2012-01-22 20:40:11

These two examples result in the same thing. However, the first provides you with using the str variable outside of the while loop; the second is not.

@Abhishek Bhandari 2012-01-20 04:33:54

Truly, the question stated above is an programming issue. How would you like to program your code? Where do you need the 'STR' to be accessed? There is no use of declaring a variable which is used locally as a global variable. Basics of programming I believe.

@ab02 2012-01-10 13:17:38

Declaring inside the loop limits the scope of the respective variable. It all depends on the requirement of the project on the scope of the variable.

@Morten Madsen 2015-09-18 12:22:17

One solution to this problem could be to provide a variable scope encapsulating the while loop:

{
  // all tmp loop variables here ....
  // ....
  String str;
  while(condition){
      str = calculateStr();
      .....
  }
}

They would be automatically de-reference when the outer scope ends.

@Naveen Goyal 2015-09-10 12:09:16

I think the best resource to answer your question would be the following post:

Difference between declaring variables before or in loop?

According to my understanding this thing would be language dependent. IIRC Java optimises this, so there isn't any difference, but JavaScript (for example) will do the whole memory allocation each time in the loop.In Java particularly I think the second would run faster when done profiling.

@Ganesa Vijayakumar 2015-05-07 08:39:56

The str variable will be available and reserved some space in memory even after while executed below code.

 String str;
    while(condition){
        str = calculateStr();
        .....
    }

The str variable will not be available and also the memory will be released which was allocated for str variable in below code.

while(condition){
    String str = calculateStr();
    .....
}

If we followed the second one surely this will reduce our system memory and increase performance.

@Jay Tomten 2012-01-10 13:03:20

Declaring String str outside of the wile loop allows it to be referenced inside & outside the while loop. Declaring String str inside of the while loop allows it to only be referenced inside the while loop.

@Rémi Doolaeghe 2012-11-22 10:12:13

You have a risk of NullPointerException if your calculateStr() method returns null and then you try to call a method on str.

More generally, avoid having variables with a null value. It stronger for class attributes, by the way.

@Desert Ice 2012-11-22 15:32:02

This is no way related to the question. The probability of NullPointerException(on future function calls) would not depend on how a variable is declared.

@Rémi Doolaeghe 2012-11-22 16:32:52

I don't think so, because the question is "What is the best way to do it ?". IMHO I would prefer a safer code.

@user207421 2014-07-01 04:17:50

There is zero risk of a NullPointerException. If this code attempted to return str; it would encounter a compilation error.

@Chandra Sekhar 2012-01-21 20:26:46

Declaring objects in the smallest scope improve readability.

Performance doesn't matter for today's compilers.(in this scenario)
From a maintenance perspective, 2nd option is better.
Declare and initialize variables in the same place, in the narrowest scope possible.

As Donald Ervin Knuth told:

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil"

i.e) situation where a programmer lets performance considerations affect the design of a piece of code. This can result in a design that is not as clean as it could have been or code that is incorrect, because the code is complicated by the optimization and the programmer is distracted by optimizing.

@assylias 2012-09-27 08:00:22

"2nd option has slightly faster performance" => have you measured it? According to one of the answers, the bytecode is the same so I don't see how performance could be different.

@assylias 2012-09-27 15:38:01

I'm sorry but that's really not the right way to test the performance of a java program (and how can you test the performance of an infinite loop anyway?)

@assylias 2012-09-27 15:49:06

I agree with your other points - it's just that I believe that there is no performance difference.

@PrimosK 2012-01-16 09:39:49

I compared the byte code of those two (similar) examples:

Let's look at 1. example:

package inside;

public class Test {
    public static void main(String[] args) {
        while(true){
            String str = String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

after javac Test.java, javap -c Test you'll get:

public class inside.Test extends java.lang.Object{
public inside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

Let's look at 2. example:

package outside;

public class Test {
    public static void main(String[] args) {
        String str;
        while(true){
            str =  String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

after javac Test.java, javap -c Test you'll get:

public class outside.Test extends java.lang.Object{
public outside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

The observations shows that there is no difference among those two examples. It's the result of JVM specifications...

But in the name of best coding practice it is recommended to declare the variable in the smallest possible scope (in this example it is inside the loop, as this is the only place where the variable is used).

@user207421 2012-04-22 23:34:40

It is the result of the JVM Soecification, not 'compiler optimization'. The stack slots required by a method are all allocated on entry to the method. That's how the bytecode is specified.

@Serge 2012-09-27 08:12:41

@Arhimed there is one more reason to put it inside the loop (or just '{}' block): the compiler will reuse the memory allocated in the stack frame for the variable in another scope if you declare in that other scope some over variable.

@Mithun Khatri 2014-12-05 04:12:54

If its looping thru a list of data objects, then will it make any difference for bulk of data? Probably 40 thousands.

@skia.heliou 2015-01-21 19:32:27

For any of you final lovers: declaring str as final in the inside package case also makes no difference =)

@James Jithin 2012-01-23 06:54:08

According to Google Android Development guide, the variable scope should be limited. Please check this link:

Limit Variable Scope

@vikiiii 2012-01-23 04:53:25

Variables should be declared as close to where they are used as possible.

It makes RAII (Resource Acquisition Is Initialization) easier.

It keeps the scope of the variable tight. This lets the optimizer work better.

@Cratylus 2012-01-10 13:05:25

If you don't need to use the str after the while loop (scope related) then the second condition i.e.

  while(condition){
        String str = calculateStr();
        .....
    }

is better since if you define an object on the stack only if the condition is true. I.e. use it if you need it

@Philipp Wendler 2012-01-10 13:07:57

Note that even in the first variant, no object is constructed if the condition is false.

@Cratylus 2012-01-10 13:20:08

@ Phillip: Yes you are right. My bad. I was thinking as it is now.What do you think?

@Philipp Wendler 2012-01-10 13:23:41

Well "defining an object on the stack" is a somewhat weird term in the Java world. Also, allocating a variable on the stack is usually a noop at runtime, so why bother? Scoping to help the programmer is the real issue.

@Azodious 2012-01-10 13:04:42

if you want to use str outside looop also; declare it outside. otherwise, 2nd version is fine.

@Jan Zyka 2012-01-10 13:03:38

Inside, the less scope the variable is visible into the better.

Related Questions

Sponsored Content

24 Answered Questions

[SOLVED] How do I declare and initialize an array in Java?

  • 2009-07-29 14:22:27
  • bestattendance
  • 4349904 View
  • 1954 Score
  • 24 Answer
  • Tags:   java arrays

30 Answered Questions

[SOLVED] Simple way to repeat a String in java

  • 2009-08-05 19:14:38
  • Ethan Heilman
  • 455580 View
  • 547 Score
  • 30 Answer
  • Tags:   java string

10 Answered Questions

[SOLVED] Improve INSERT-per-second performance of SQLite?

35 Answered Questions

[SOLVED] How do I break out of nested loops in Java?

  • 2009-05-20 09:07:43
  • boutta
  • 1094546 View
  • 1752 Score
  • 35 Answer
  • Tags:   java loops

13 Answered Questions

[SOLVED] Emulate a do-while loop in Python?

26 Answered Questions

[SOLVED] How does the Java 'for each' loop work?

1 Answered Questions

2 Answered Questions

[SOLVED] Can't declare variable inside While loop

9 Answered Questions

[SOLVED] Variable declaration inside a loop

  • 2010-01-05 08:59:15
  • Amit
  • 2547 View
  • 8 Score
  • 9 Answer
  • Tags:   java

Sponsored Content