278

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?

BSMP
  • 4,596
  • 8
  • 33
  • 44
Harry Joy
  • 58,650
  • 30
  • 162
  • 207
  • Does this answer your question? [Difference between declaring variables before or in loop?](https://stackoverflow.com/questions/407255/difference-between-declaring-variables-before-or-in-loop) – user202729 Oct 17 '22 at 14:07

20 Answers20

330

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.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • 2
    Query on last paragraph: If it was another then String which is not immutable then does it affect? – Harry Joy Jan 11 '12 at 04:15
  • 2
    @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 Jan 11 '12 at 04:23
  • 7
    @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. – Mike Nakis Jan 11 '12 at 04:23
  • 1
    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? – Nirmal- thInk beYond Jan 11 '12 at 04:37
  • @Nirmal-thInkbeYond I just answered this using StringBuilder as an example. Read 3 comments above. – Mike Nakis Jan 11 '12 at 04:39
  • 2
    @MikeNakis i thing you are thinking in very narrow scope. – Siten Jan 11 '12 at 04:45
  • @MikeNakis What will be behaviour of method stack in both the cases? How many times the variable type is put into stack frame? – Siten Jan 11 '12 at 04:48
  • @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. – Mike Nakis Jan 11 '12 at 04:51
  • @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. – Siten Jan 11 '12 at 04:57
  • @MikeNakis would you agree with the answer I provided or did I miss something? – PrimosK Jan 16 '12 at 10:01
  • @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 Jan 16 '12 at 10:33
  • 6
    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. – Mike Nakis Jan 16 '12 at 10:36
  • 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. – Nick Dec 28 '17 at 20:08
  • 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. – Phil Goetz Apr 12 '18 at 04:07
  • @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. – Mike Nakis Apr 13 '18 at 14:25
  • @MikeNakis The second one is the recommendation in this case but in every loop a new `str` variable will be created and it will consume the memory. How do you thing about that? – Hoang Nguyen Nov 27 '20 at 19:03
322

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).

PrimosK
  • 13,848
  • 10
  • 60
  • 78
  • 6
    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. – user207421 Apr 22 '12 at 23:34
  • 2
    @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. – Serge Sep 27 '12 at 08:12
  • 1
    If its looping thru a list of data objects, then will it make any difference for bulk of data? Probably 40 thousands. – Mithun Khatri Dec 05 '14 at 04:12
  • 9
    For any of you `final` lovers: declaring `str` as `final` in the `inside` package case **also** makes no difference =) – nikodaemus Jan 21 '15 at 19:32
34

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.

cHao
  • 84,970
  • 20
  • 145
  • 172
Chandra Sekhar
  • 16,256
  • 10
  • 67
  • 90
  • 1
    *"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 Sep 27 '12 at 08:00
  • 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 Sep 27 '12 at 15:38
  • I agree with your other points - it's just that I believe that there is no performance difference. – assylias Sep 27 '12 at 15:49
14

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

Azodious
  • 13,752
  • 1
  • 36
  • 71
13

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

Onur Günduru
  • 451
  • 4
  • 14
  • Invalid testing methodology, and you don't provide any explanation of your results. – user207421 Jul 01 '14 at 04:16
  • 1
    @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? – Onur Günduru Jul 04 '14 at 18:02
  • 2
    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. – Hardcoded Jan 02 '15 at 16:17
  • @Hardcoded better tests/micro benchmarking with caliper only for double and 100M loops. Results online, if you want other cases feel free to edit. – Onur Günduru Jan 05 '15 at 22:23
  • 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. – Hardcoded Jan 08 '15 at 09:46
  • @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... – Onur Günduru Jan 08 '15 at 10:20
  • @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. – user207421 Jul 06 '15 at 20:22
  • @EJP maybe you should take some time to understand how Calipher works or write another test case to prove yourself? – Onur Günduru Jul 09 '15 at 15:56
  • 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. – Mike Nakis Oct 04 '15 at 21:15
  • @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 – Onur Günduru Oct 05 '15 at 15:16
  • @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. – Mike Nakis Oct 05 '15 at 18:32
  • @MikeNakis thanks, I've also came across with http://java-performance.info/jmh/ might be worth to check out – Onur Günduru Oct 07 '15 at 10:24
  • @MikeNakis Looks like JMH will be the 'official' tool in Java9 for microbechmarking https://javax0.wordpress.com/2016/09/11/microbenchmarking-comes-to-java-9/ – Onur Günduru Apr 18 '17 at 10:50
8

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.

Morten Madsen
  • 111
  • 2
  • 6
8

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

Jan Zyka
  • 17,460
  • 16
  • 70
  • 118
7

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

Cratylus
  • 52,998
  • 69
  • 209
  • 339
  • 3
    Note that even in the first variant, no object is constructed if the condition is false. – Philipp Wendler Jan 10 '12 at 13:07
  • @ Phillip: Yes you are right. My bad. I was thinking as it is now.What do you think? – Cratylus Jan 10 '12 at 13:20
  • 1
    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. – Philipp Wendler Jan 10 '12 at 13:23
4

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.

Community
  • 1
  • 1
Naveen Goyal
  • 446
  • 1
  • 3
  • 12
3

Declaring String str outside of the while 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 that while loop.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Jay Tomten
  • 1,657
  • 1
  • 14
  • 23
3

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.

vikiiii
  • 9,246
  • 9
  • 49
  • 68
3

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

Limit Variable Scope

James Jithin
  • 10,183
  • 5
  • 36
  • 51
2

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...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pavan
  • 711
  • 2
  • 6
  • 17
  • 1
    except probably in this way: [link](http://stackoverflow.com/questions/6133586/should-i-declare-variables-as-close-as-possible-to-the-scope-where-they-will-be/22245471#22245471) – Dainius Kreivys Mar 07 '14 at 09:21
1

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ab02
  • 11
  • 3
1

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abhishek Bhandari
  • 613
  • 1
  • 5
  • 16
0

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.

Selva
  • 338
  • 2
  • 12
Ganesa Vijayakumar
  • 2,422
  • 5
  • 28
  • 41
0

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.

Sanjit
  • 3
  • 4
0

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
olyanren
  • 1,448
  • 4
  • 24
  • 42
-1

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rt15
  • 87
  • 1
  • 1
  • 7
  • 2
    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. – Hardcoded Jan 02 '15 at 16:26
  • Dangerous in multithreaded environment??? Please explain why. We are talking about a local variable. It is created at each call of the method. – rt15 Jan 05 '15 at 09:15
  • 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 Jan 08 '15 at 08:41
  • Ps: Your setValue Method should be `bigStuff[(int) (value % STUFF_SIZE)] = value;` (Try a value of 2147483649L) – Hardcoded Jan 08 '15 at 08:44
  • Speaking about sideeffects: Have you compared the results of your methods? – Hardcoded Jan 08 '15 at 08:49
  • 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. – rt15 Jan 09 '15 at 09:31
-2

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.

Stijn Geukens
  • 15,454
  • 8
  • 66
  • 101
Rémi Doolaeghe
  • 2,262
  • 3
  • 31
  • 50
  • 2
    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. – Desert Ice Nov 22 '12 at 15:32
  • 1
    I don't think so, because the question is "What is the best way to do it ?". IMHO I would prefer a safer code. – Rémi Doolaeghe Nov 22 '12 at 16:32
  • 1
    There is zero risk of a `NullPointerException.` If this code attempted to `return str;` it would encounter a compilation error. – user207421 Jul 01 '14 at 04:17