Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the Java foreach loop create a new object?

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
}
like image 842
CLo Avatar asked Feb 01 '13 05:02

CLo


2 Answers

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 in Objects?

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.

like image 101
Matt Ball Avatar answered Sep 29 '22 09:09

Matt Ball


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.

like image 22
user207421 Avatar answered Sep 29 '22 09:09

user207421