[java] How to change value of ArrayList element in java

Please help me with below code , I get the same output even after changing the value

import java.util.*;

class Test {
    public static void main(String[] args) {
        ArrayList<Integer> a = new ArrayList<Integer>();

       // added 0-9 to ArrayList        
          for(int i=0;i<9;i++)
            a.add(new Integer(i));

        // initialize the Iterator
        Iterator<Integer> i = a.iterator();

        // changed the value of first element in List
        if(i.hasNext()) {
            Integer x = i.next();
            x = Integer.valueOf(9);
        }

        // initialized the iterator again and print all the elements
        i = a.iterator();
        while(i.hasNext())
            System.out.print(i.next());
    }
}    

//Output : 012345678

Value 9 is not updating.

This question is related to java arraylist

The answer is


The list is maintaining an object reference to the original value stored in the list. So when you execute this line:

Integer x = i.next();

Both x and the list are storing a reference to the same object. However, when you execute:

x = Integer.valueOf(9);

nothing has changed in the list, but x is now storing a reference to a different object. The list has not changed. You need to use some of the list manipulation methods, such as

list.set(index, Integer.valueof(9))

Note: this has nothing to do with the immutability of Integer, as others are suggesting. This is just basic Java object reference behaviour.


Here's a complete example, to help explain the point. Note that this makes use of the ListIterator class, which supports removing/setting items mid-iteration:

import java.util.*;

public class ListExample {

  public static void main(String[] args) {

    List<Foo> fooList = new ArrayList<Foo>();
    for (int i = 0; i < 9; i++)
      fooList.add(new Foo(i, i));

    // Standard iterator sufficient for altering elements
    Iterator<Foo> iterator = fooList.iterator();

    if (iterator.hasNext()) {
      Foo foo = iterator.next();
      foo.x = 99;
      foo.y = 42;
    }

    printList(fooList);    

    // List iterator needed for replacing elements
    ListIterator<Foo> listIterator = fooList.listIterator();

    if (listIterator.hasNext()) {
      // Need to call next, before set.
      listIterator.next();
      // Replace item returned from next()
      listIterator.set(new Foo(99,99));
    }

    printList(fooList);
  }

  private static void printList(List<?> list) {
    Iterator<?> iterator = list.iterator();
    while (iterator.hasNext()) {
      System.out.print(iterator.next());
    }
    System.out.println();
  }

  private static class Foo {
    int x;
    int y;

    Foo(int x, int y) {
      this.x = x;
      this.y = y;
    }

    @Override
    public String toString() {
      return String.format("[%d, %d]", x, y);
    }
  }
}

This will print:

[99, 42][1, 1][2, 2][3, 3][4, 4][5, 5][6, 6][7, 7][8, 8]
[99, 99][1, 1][2, 2][3, 3][4, 4][5, 5][6, 6][7, 7][8, 8]

Use the set method to replace the old value with a new one.

list.set( 2, "New" );

I agree with Duncan ...I have tried it with mutable object but still get the same problem... I got a simple solution to this... use ListIterator instead Iterator and use set method of ListIterator

ListIterator<Integer> i = a.listIterator();
//changed the value of first element in List
Integer x =null;
        if(i.hasNext()) {
            x = i.next();
            x = Integer.valueOf(9);
        }
    //set method sets the recent iterated element in ArrayList
    i.set(x);
        //initialized the iterator again and print all the elements
        i = a.listIterator();
        while(i.hasNext())
        System.out.print(i.next());

But this constraints me to use this only for ArrayList only which can use ListIterator...i will have same problem with any other Collection


Change it to for(int i=0;i<=9;i++)


Where you say you're changing the value of the first element;

x = Integer.valueOf(9);

You're changing x to point to an entirely new Integer, but never using it again. You're not changing the collection in any way.

Since you're working with ArrayList, you can use ListIterator if you want an iterator that allows you to change the elements, this is the snippet of your code that would need to be changed;

//initialize the Iterator
ListIterator<Integer> i = a.listIterator();

//changed the value of frist element in List
if(i.hasNext()) {
    i.next();
    i.set(Integer.valueOf(9));    // Change the element the iterator is currently at
}

// New iterator, and print all the elements
Iterator iter = a.iterator();
while(iter.hasNext())
    System.out.print(iter.next());

>> 912345678

Sadly the same cannot be extended to other collections like Set<T>. Implementation details (a HashSet for example being implemented as a hash table and changing the object could change the hash value and therefore the iteration order) makes Set<T> a "add new/remove only" type of data structure, and changing the content at all while iterating over it is not safe.


I think the problem is that you think the statement ...

x = Integer.valueOf(9);

... causes that the value of '9' get 'stored' into(!) the Object on which x is referencing.

But thats wrong.

Instead the statement causes something similar as if you would call

x = new Integer(9); 

If you have a look to the java source code, you will see what happens in Detail.

Here is the code of the "valueOf(int i)" method in the "Integer" class:

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

and further, whenever the IntegerCache class is used for the first time the following script gets invoked:

static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

You see that either a new Integer Object is created with "new Integer(i)" in the valueOf method ... ... or a reference to a Integer Object which is stored in the IntegerCache is returned.

In both cases x will reference to a new Object.

And this is why the reference to the Object in your list get lost when you call ...

x = Integer.valueOf(9);

Instead of doing so, in combination with a ListIterator use ...

i.set(Integer.valueOf(9));

... after you got the element you want to change with ...

i.next();

You're trying to change the value in the list, but all you're doing is changing the reference of x. Doing the following only changes x, not anything in the collection:

x = Integer.valueOf(9);

Additionally, Integer is immutable, meaning you can't change the value inside the Integer object (which would require a different method to do anyway). This means you need to replace the whole object. There is no way to do this with an Iterator (without adding your own layer of boxing). Do the following instead:

a.set(0, 9);