Properly removing an Integer from a List

前端 未结 8 1671
面向向阳花
面向向阳花 2020-11-22 03:57

Here\'s a nice pitfall I just encountered. Consider a list of integers:

List list = new ArrayList();
list.add(5);
list.add(6);         


        
相关标签:
8条回答
  • 2020-11-22 04:46

    Java always calls the method that best suits your argument. Auto boxing and implicit upcasting is only performed if there's no method which can be called without casting / auto boxing.

    The List interface specifies two remove methods (please note the naming of the arguments):

    • remove(Object o)
    • remove(int index)

    That means that list.remove(1) removes the object at position 1 and remove(new Integer(1)) removes the first occurrence of the specified element from this list.

    0 讨论(0)
  • 2020-11-22 04:46

    Note that even if the VM did not do the right thing, which it does, you could still ensure proper behaviour by using the fact that remove(java.lang.Object) operates on arbitrary objects:

    myList.remove(new Object() {
      @Override
      public boolean equals(Object other) {
        int k = ((Integer) other).intValue();
        return k == 1;
      }
    }
    
    0 讨论(0)
  • 2020-11-22 04:48

    Any educated guess on what happens when you execute list.remove(1)? What about list.remove(new Integer(1))?

    There is no need to guess. The first case will result in List.remove(int) being called, and the element at position 1 will be removed. The second case will result in List.remove(Integer) being called, and the element whose value is equal to Integer(1) will be removed. In both cases, the Java compiler selects the closest matching overload.

    Yes, there is potential for confusion (and bugs) here, but it is a fairly uncommon use-case.

    When the two List.remove methods were defined in Java 1.2, the overloads were not ambiguous. The problem only arose with the introduction of generics and autoboxing in Java 1.5. In hind-sight, it would have been better if one of the remove methods had been given a different name. But it is too late now.

    0 讨论(0)
  • 2020-11-22 04:48

    Well here is the trick.

    Let's take two examples here:

    public class ArrayListExample {
    
    public static void main(String[] args) {
        Collection<Integer> collection = new ArrayList<>();
        List<Integer> arrayList = new ArrayList<>();
    
        collection.add(1);
        collection.add(2);
        collection.add(3);
        collection.add(null);
        collection.add(4);
        collection.add(null);
        System.out.println("Collection" + collection);
    
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(null);
        arrayList.add(4);
        arrayList.add(null);
        System.out.println("ArrayList" + arrayList);
    
        collection.remove(3);
        arrayList.remove(3);
        System.out.println("");
        System.out.println("After Removal of '3' :");
        System.out.println("Collection" + collection);
        System.out.println("ArrayList" + arrayList);
    
        collection.remove(null);
        arrayList.remove(null);
        System.out.println("");
        System.out.println("After Removal of 'null': ");
        System.out.println("Collection" + collection);
        System.out.println("ArrayList" + arrayList);
    
      }
    
    }
    

    Now let's have a look at the output:

    Collection[1, 2, 3, null, 4, null]
    ArrayList[1, 2, 3, null, 4, null]
    
    After Removal of '3' :
    Collection[1, 2, null, 4, null]
    ArrayList[1, 2, 3, 4, null]
    
    After Removal of 'null': 
    Collection[1, 2, 4, null]
    ArrayList[1, 2, 3, 4]
    

    Now let's analyze the output:

    1. When 3 is removed from the collection it calls the remove() method of the collection which takes Object o as parameter. Hence it removes the object 3. But in arrayList object it is overridden by index 3 and hence the 4th element is removed.

    2. By the same logic of Object removal null is removed in both cases in the second output.

    So to remove the number 3 which is an object we will explicitly need to pass 3 as an object.

    And that can be done by casting or wrapping using the wrapper class Integer.

    Eg:

    Integer removeIndex = Integer.valueOf("3");
    collection.remove(removeIndex);
    
    0 讨论(0)
  • 2020-11-22 04:53

    list.remove(4) is an exact match of list.remove(int index), so it will be called. If you want to call list.remove(Object) do the following: list.remove((Integer)4).

    0 讨论(0)
  • 2020-11-22 04:55

    I don't know about 'proper' way, but the way you suggested works just fine:

    list.remove(int_parameter);
    

    removes element at given position and

    list.remove(Integer_parameter);
    

    removes given object from the list.

    It's because VM at first attempts to find method declared with exactly the same parameter type and only then tries autoboxing.

    0 讨论(0)
提交回复
热议问题