Правильное удаление целого из списка <Integer>

Здесь хорошая ошибка, с которой я только что столкнулся. Рассмотрим список целых чисел:

List<Integer> list = new ArrayList<Integer>();
list.add(5);
list.add(6);
list.add(7);
list.add(1);

Любое образованное предположение о том, что происходит при выполнении list.remove(1)? Что насчет list.remove(new Integer(1))? Это может вызвать некоторые неприятные ошибки.

Каков правильный способ разграничения между remove(int index), который удаляет элемент из заданного индекса и remove(Object o), который удаляет элемент по ссылке при работе со списками целых чисел?


Главное здесь рассмотреть один @Nikita, упомянутый - точное сопоставление параметров имеет преимущество перед автоматическим боксом.

Ответ 1

Java всегда вызывает метод, который наилучшим образом соответствует вашему аргументу. Автоматический бокс и неявное восходящее движение выполняются только в том случае, если нет метода, который можно вызвать без каста/автоматического бокса.

Интерфейс List указывает два метода удаления (обратите внимание на именование аргументов):

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

Это означает, что list.remove(1) удаляет объект в позиции 1 и remove(new Integer(1)) удаляет первое вхождение указанного элемента из этого списка.

Ответ 2

Вы можете использовать кастинг

list.remove((int) n);

и

list.remove((Integer) n);

Не имеет значения, если n - это int или Integer, метод всегда будет называть тот, который вы ожидаете.

Использование (Integer) n или Integer.valueOf(n) более эффективно, чем new Integer(n), поскольку первые два могут использовать кеш Integer, тогда как позже будет всегда создавать объект.

Ответ 3

Я не знаю о "правильном" способе, но способ, который вы предложили, работает очень хорошо:

list.remove(int_parameter);

удаляет элемент в заданном положении и

list.remove(Integer_parameter);

удаляет данный объект из списка.

Это потому, что VM сначала пытается найти метод, объявленный с точно таким же типом параметра, и только затем пытается autoboxing.

Ответ 4

list.remove(4) является точным соответствием list.remove(int index), поэтому он будет вызываться. Если вы хотите вызвать list.remove(Object), выполните следующие действия: list.remove((Integer)4).

Ответ 5

Любое образованное предположение о том, что происходит при выполнении list.remove(1)? Как насчет list.remove(новый Integer (1))?

Нет необходимости гадать. Первый случай приведет к вызову List.remove(int), и элемент в позиции 1 будет удален. Второй случай приведет к вызову List.remove(Integer), и элемент, значение которого равно Integer(1), будет удалено. В обоих случаях компилятор Java выбирает ближайшую совпадающую перегрузку.

Да, здесь есть путаница (и ошибки), но это довольно необычный случай использования.

Когда два метода List.remove были определены в Java 1.2, перегрузки не были двусмысленными. Проблема возникла только с введением генериков и автобоксинга в Java 1.5. На заднем плане было бы лучше, если бы одному из методов удаления присвоено другое имя. Но уже слишком поздно.

Ответ 6

Обратите внимание, что даже если виртуальная машина не сделала правильные вещи, что она делает, вы все равно можете обеспечить правильное поведение, используя тот факт, что remove(java.lang.Object) работает с произвольными объектами:

myList.remove(new Object() {
  @Override
  public boolean equals(Object other) {
    int k = ((Integer) other).intValue();
    return k == 1;
  }
}

Ответ 7

Просто мне понравилось следующее, как было предложено #decitrig в принятом ответе на первый комментарий.

list.remove(Integer.valueOf(intereger_parameter));

Это помогло мне. Еще раз спасибо #decitrig за ваш комментарий. Это может помочь кому-то.

Ответ 8

Ну вот трюк.

Здесь можно привести два примера:

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);

  }

}

Теперь посмотрим на результат:

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]

Теперь проанализируем вывод:

  • Когда 3 удаляется из коллекции, он вызывает метод remove() коллекции, который принимает Object o как параметр. Следовательно, он удаляет объект 3. Но в объекте arrayList он переопределяется индексом 3 и, следовательно, удаляется 4-й элемент.

  • По той же логике удаления Object null в обоих случаях удаляется во втором случае.

Итак, чтобы удалить номер 3, который является объектом, нам явно нужно передать 3 как object.

И это может быть сделано путем литья или обертывания с использованием класса-оболочки Integer.

Например:

Integer removeIndex = Integer.valueOf("3");
collection.remove(removeIndex);

Ответ 9

Простой код Java Объяснение для визуализации разницы между ArrayList.remove(Object o) и ArrayList.remove(int index)

КОД:

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(7);
list.add(4);
list.add(5);
list.add(6);
list.add(7);

for (int a = 0; a < list.size(); a++) {
    System.out.print("" + list.get(a));
}

System.out.print("  ");

//CASE 1: We are removing data object 7.
list.remove(new Integer(7));

for (int a = 0; a < list.size(); a++) {
    System.out.print("" + list.get(a));
}

System.out.print("  ");

//CASE 2: Again we are removing data object 7.
list.remove(new Integer(7));

for (int a = 0; a < list.size(); a++) {
    System.out.print("" + list.get(a));
}

System.out.print("  ");

//CASE 3: We are removing data at index 1
list.remove(1);

for (int a = 0; a < list.size(); a++) {
    System.out.print("" + list.get(a));
}

ВЫХОД:

1274567
124567
12456
1456

ОБЪЯСНЕНИЕ:

CASE 1: Мы удаляем первый объект Integer с данными 7.

CASE 2: Затем мы снова делаем то же, что и в CASE 1 из оставшихся данных.

CASE 3: Мы удаляем данные в позиции индекса.

ЗАКЛЮЧЕНИЕ:

Пример ArrayList<Integer>, используемый в приведенном выше java-коде: ArrayList.remove(Integer object) просто удалит конкретный объект Integer, который сначала встречается в ArrayList. Однако ArrayList.remove(int index) всегда удаляет элемент массива в заданной позиции индекса.

БОЛЬШЕ:

Мы не можем объявить ArrayList<int>, потому что он int является основным типом данных. Любой класс, который имеет базовый класс Object, указан только в типичном типе ArrayList. например: ArrayList<String>, ArrayList<Integer> и т.д.