18

I have following two scenarios:

1. int value as parameter

int intNum = 2;
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.remove(intNum);
System.out.println(list.size());
// output: 2

2. long value as parameter

long longNum = 2;
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.remove(longNum);
System.out.println(list.size());
// output: 3

I am passing 2 as the value in both cases, but I am getting a different size value of the List. What is the actual reason for this behavior?

Properly removing an Integer from a List does not explain about build-in data type having same value but having behavior differently as asked above

Community
  • 1
  • 1
Farooque
  • 3,616
  • 2
  • 29
  • 41
  • Now that you see that list.remove(2) is removing element at index 2 and not integer 2, you should make a point to explicitly cast to "int" or "Integer" or you only risk to confuse yourself. – Neil May 20 '15 at 15:40
  • This could be a nice question for a tech interview. – beetstra May 20 '15 at 19:23

7 Answers7

25

Autoboxing

The list.remove method is overloaded, and the two different signatures are used for different purposes. One, list.remove(int), removes an item based on its index, and the other one, list.remove(Object), removes an item based on object equality. Your first situation triggers the first type, and your second example (with a long longNum), triggers the second type, autoboxing the long primitive to a java.lang.Long object. This is not equal to the java.lang.Integer (autoboxed) values added to the list, and thus will not remove anything from the list and the size will remain same.

Farooque
  • 3,616
  • 2
  • 29
  • 41
beetstra
  • 7,942
  • 5
  • 40
  • 44
  • 7
    And the reason `Object` overload is chosen in the second case is because `long` cannot be converted to `int`. `Object` overload is the only one that can possibly apply, –  May 20 '15 at 12:36
  • 1
    Even if the first situation triggered the second type, the result would be different. – xehpuk May 20 '15 at 21:58
5

From the List.remove() documentation :

remove(int index) Removes the element at the specified position in this list (optional operation).

remove(Object o) Removes the first occurrence of the specified element from this list, if it is present (optional operation).

removeAll(Collection c) Removes from this list all of its elements that are contained in the specified collection (optional operation).

If you second example is indeed a long, it won't be removed (since it uses the second remove method).

User404
  • 2,152
  • 2
  • 27
  • 35
5

Be careful: The first one removes the Integer at index = 2. See ArrayList.remove(int)

The second one tries to remove an object with ArrayList.remove(Object), but the object you want to remove does not exist because it's a Long object.

dejvuth
  • 6,986
  • 3
  • 33
  • 36
4

The List interface contains two remove() methods - remove(Object) and remove(int).

The implementation of remove(Object) in Java 6 is as follows:

public boolean remove(Object o) {
if (o == null) {
        for (int index = 0; index < size; index++)
    if (elementData[index] == null) {
        fastRemove(index);
        return true;
    }
} else {
    for (int index = 0; index < size; index++)
    if (o.equals(elementData[index])) {
        fastRemove(index);
        return true;
    }
    }
return false;
}

The implementation of remove(int) in Java 6 is:

public E remove(int index) {
RangeCheck(index);

modCount++;
E oldValue = (E) elementData[index];

int numMoved = size - index - 1;
if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
             numMoved);
elementData[--size] = null; // Let gc do its work

return oldValue;
}

In your first example, you're actually calling the remove(int) method, which removes the object at the specified index. In this case, you specified index 2, which is actually the value "3".

In your second example, you're calling the remove(Object) method, since there isn't a remove(long) method and a long won't be converted into an int. Based on the implementation of the remove(Object) method, it looks for object equality. Since your list contains objects of type Integer and you're providing a Long, nothing will match it.

The following method is probably a better example of what's happening:

public static void main(String[] args) {
    ArrayList<Integer> list;

    System.out.println("Removing intNum");
    int intNum = 2;
    list = new ArrayList<Integer>();
    list.add(1);
    list.add(2);
    list.add(3);
    System.out.println("List = " + list);
    list.remove(intNum);
    System.out.println("List = " + list);

    System.out.println("Removing longNum");
    long longNum = 2;
    list = new ArrayList<Integer>();
    list.add(1);
    list.add(2);
    list.add(3);
    System.out.println("List = " + list);
    list.remove(longNum);
    System.out.println("List = " + list);
}

The output of this code is:

Removing intNum
List = [1, 2, 3]
List = [1, 2]
Removing longNum
List = [1, 2, 3]
List = [1, 2, 3]
Thomas Owens
  • 114,398
  • 98
  • 311
  • 431
3

Calling List.remove() with an int argument will match the signature remove(int index) and the item on index list[2] will be removed regardless if the list has an Integer item with value of 2.

Calling List.remove() with an long argument will cause the compiler to do auto-boxing into a Long object and match the signature remove(Object o). The list will iterate, asking if o.equals(each item) and as was mentioned before, Long does not equal Integer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sharon Ben Asher
  • 13,849
  • 5
  • 33
  • 47
2

When you were doing list.remove(intNum); it was performing the remove(int index); signature of the List class, which remove the item of the given index.

However when you did list.remove(longNum); (considering you meant longNum to be long), it performed the boolean remove(Object o); signature of List class, which checks if the object is present in the list, and if yes removes it.

Since the list is an Integer list it could not find the object and did not remove anything, and that is why the second result is 3, nothing is deleted.

Soumitri Pattnaik
  • 3,246
  • 4
  • 24
  • 42
2

List in Collection has two overloaded methods 1. public E remove(int index) 2. public boolean remove(Object o)

In your case second method gets called. since you are passing long (implicit casting to Long wrapper class so Object class ).

Now List.remove(longNum) removes the element with the lowest index i such that (longNum==null ? get(i)==null : longNum.equals(get(i) ) ) (if such an element exists).

Now in Your case when the counter came at second position (i.e i=1). longNum.equals(get(1)) returns false because get(1) returns the Object of java.lang.Integer with value=2 and longNum is an instance of java.lang.Long with value=2. So equals method returns false thus it does not delete the element.

You can check the type of the value by its class Name

   System.out.println(" Element Value :"+list.get(1));
   System.out.println(" Element Class :"+list.get(1).getClass());