Will Java create a new object each time a foreach loop is entered? I'm not talking about each iteration, but if you have a foreach loop that is used multiple times, is it creating objects each time?
Simple Example:
for(Object o : Objects)
{
for(Object p : Objects2)
{
}
}
Would there only be one p
per execution, or would p
be instantiated for each Object o
?
Does the Garbage Collector have to recover an object from the foreach loop each time it is exited?
More specifically, I'm writing some Android based game code. It will iterate over all the game objects at a given rate per second, or as fast as it can depending on the circumstances.
It may be a case of premature optimization, but if using an explicit for
or while
loop can guarantee me that I won't have excess garbage collection from my loops, then I can establish that as a coding standard for the project.
More specifically:
public void update()
{
for(GameObject gObj : gameObjects)
{
gObj.update();
}
}
With update()
being called from a thread designed to make the calls based on the timing I described before.
Update:
I am asking if there is a new Reference p
being created for each o
in Objects
. Not if it copies the objects in Objects2
. So does the VM have to create a new Reference p
, and then does it collect that reference between iterations of the outter loop? And more specifically in my case, does it collect the reference between method calls?
Update: From comments on Matt Ball's answer. Which would create less Garbage Collection work?
//Loop just to have it run a number of times
//Could be running the inner foreach numerous time for any reason
for(int i = 0; i < 1000; i++)
{
for(Object o : Objects)
{
o.update();
}
}
vs.
Iterator<Object> iter;
//Loop just to have it run a number of times
//Could be running the inner foreach numerous time for any reason
for(int i = 0; i < 1000; i++)
{
iter = Objects.iterator();
while(iter.hasNext());
{
iter.getNext().update();
}
}
Update: Comparing scopes:
import java.util.ArrayList;
import java.util.Iterator;
public class TestLoops
{
public static Iterator<Object> it;
public static ArrayList<Object> objects;
public static void main(String... args)
{
objects = new ArrayList<Object>();
it = objects.iterator();
it = objects.iterator();
//Every time we start a foreach loop, does it creates a new reference?
Iterator<Object> newIt1 = objects.iterator();
Iterator<Object> newIt2 = objects.iterator();
}
}
Produces this Bytecode:
public class TestLoops {
public static java.util.Iterator<java.lang.Object> it;
public static java.util.ArrayList<java.lang.Object> objects;
public TestLoops();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String...);
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: putstatic #4 // Field objects:Ljava/util/ArrayList;
10: getstatic #4 // Field objects:Ljava/util/ArrayList;
13: invokevirtual #5 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
16: putstatic #6 // Field it:Ljava/util/Iterator;
19: getstatic #4 // Field objects:Ljava/util/ArrayList;
22: invokevirtual #5 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
25: putstatic #6 // Field it:Ljava/util/Iterator;
28: getstatic #4 // Field objects:Ljava/util/ArrayList;
31: invokevirtual #5 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
34: astore_1
35: getstatic #4 // Field objects:Ljava/util/ArrayList;
38: invokevirtual #5 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
41: astore_2
42: return
}
There is no magical object construction that happens with a for-each loop. This syntax:
for(Object o : Objects)
{
for(Object p : Objects2)
{
}
}
is only shorthand for this:
for(Iterator<Object> iter = Objects.iterator(); iter.hasNext();)
{
Object o = iter.next();
for(Iterator<Object> iter2 = Objects2.iterator(); iter2.hasNext();)
{
Object p = iter2.next();
}
}
If would there be an
iter2
reference created for every object I had inObjects
?
That depends on where Objects2
comes from. Does it come from o
? It also depends on how Objects2.iterator()
is implemented. Iterable#iterator()
is expected to return independent iterators, which means that Objects2.iterator()
would almost certainly return a new Iterator
for each invocation. But that does not say anything about whether or not iterating through the objects in Objects2
(using iter2
) creates other new objects.
This sounds like premature optimization, overall.
Which would create less Garbage Collection work?
Neither. The enhanced for loop (aka for-each loop) is simply syntactic sugar. The bytecode produced by the compiler is identical. Complete example:
package com.stackoverflow;
import java.util.Iterator;
public class Question14640184
{
public void enhancedForLoop(Iterable<Object> objects1, Iterable<Object> objects2)
{
for(Object o1 : objects1)
{
for(Object o2 : objects2)
{
// do something
}
}
}
public void iteratorForLoop(Iterable<Object> objects1, Iterable<Object> objects2)
{
for(Iterator<Object> iter1 = objects1.iterator(); iter1.hasNext();)
{
Object o1 = iter1.next();
for(Iterator<Object> iter2 = objects2.iterator(); iter2.hasNext();)
{
Object o2 = iter2.next();
}
}
}
}
Compile:
✗ javac Question14640184.java
✗ javap -c Question14640184
Compiled from "Question14640184.java"
public class com.stackoverflow.Question14640184 extends java.lang.Object{
public com.stackoverflow.Question14640184();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public void enhancedForLoop(java.lang.Iterable, java.lang.Iterable);
Code:
0: aload_1
1: invokeinterface #2, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
6: astore_3
7: aload_3
8: invokeinterface #3, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
13: ifeq 57
16: aload_3
17: invokeinterface #4, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
22: astore 4
24: aload_2
25: invokeinterface #2, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
30: astore 5
32: aload 5
34: invokeinterface #3, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
39: ifeq 54
42: aload 5
44: invokeinterface #4, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
49: astore 6
51: goto 32
54: goto 7
57: return
public void iteratorForLoop(java.lang.Iterable, java.lang.Iterable);
Code:
0: aload_1
1: invokeinterface #2, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
6: astore_3
7: aload_3
8: invokeinterface #3, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
13: ifeq 57
16: aload_3
17: invokeinterface #4, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
22: astore 4
24: aload_2
25: invokeinterface #2, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
30: astore 5
32: aload 5
34: invokeinterface #3, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
39:
So like I said, the for-each loop is only syntactic sugar.
it's something I'm just fixated on.
Move on, friendo.
It depends entirely on what the Iterable returns. If it creates a new object, so be it. If not, not. In the case of an array, for example, the elements already exist, so no object is created. Same applies to most Collections.
The one case where it almost certainly creates a new object is where the Iterable itself is the result of a function call, for example:
for (Object o : xyz.getIterable())
But this isn't a property of the for-each loop but of the function call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With