Яма, с которой сталкивается удаление ArrayList в Java

интервью Java задняя часть API

предисловие

Наиболее часто используемым являетсяArrayListиHashMapДа, это также частый гость, чтобы задавать вопросы и отвечать во время интервью. Независимо от емкости, коэффициента нагрузки и т. д., даже при простом использовании будут возникать ямы.

Удалить элемент

Часто встречающийся сценарий: просмотрите список, а затем найдите подходящие условия для удаления, например удаление всех четных чисел.

@Test
public void testRemove2(){
    List<Integer> integers = new ArrayList<>(5);
    integers.add(1);
    integers.add(2);
    integers.add(2);
    integers.add(4);
    integers.add(5);

    for (int i = 0; i < integers.size(); i++) {
        if (integers.get(i)%2==0){
            integers.remove(i);
        }
    }

    System.out.println(integers);
}

Кажется, что нет никакой проблемы.Присоединяясь к интервью, спросите лично: Что на выходе? Опять же, это действительно не так? Что опять в результате?

  • сообщить об ошибке
  • Результат - пустой список
  • Результат [1, 2, 5]

List.remove() имеет два, одинpublic E remove(int index),одинpublic boolean remove(Object o), то каков результат:

@Test
public void testRemove(){
    ArrayList<Integer> integers = Lists.newArrayList(1, 2, 3, 4);
    System.out.println(integers);
    integers.remove(1);
    System.out.println(integers);
}
  • [1, 3, 4]

Часто используется API Arrays.asList, так что же получается в результате:

@Test
public void testRemove3(){
    List<String> list = Arrays.asList("a","b");
    list.add("c");
    System.out.println(list);
}
  • Ошибка: java.lang.UnsupportedOperationException

Можно ли добиться вопроса в начале, используя foreach

@Test
public void testRemove4(){
    List<String> strings = new ArrayList<>();
    strings.add("a");
    strings.add("b");
    strings.add("c");
    strings.add("d");

    for (String string : strings) {
        strings.remove(string);
    }
}
  • Нет, сообщается об ошибке java.util.ConcurrentModificationException

Для проблем с производительностью мы рекомендуем извлечь вычисление list.size

@Test
public void testRemove5(){
    List<String> strings = new ArrayList<>();
    strings.add("a");
    strings.add("b");
    strings.add("c");
    strings.add("d");

    int size = strings.size();
    for (int i = 0; i < size; i++) {
        strings.remove(i);
    }

}
  • Ошибка: java.lang.IndexOutOfBoundsException: индекс: 2, размер: 2
  • Это хорошая привычка, вместо того, чтобы вычислять размер каждый раз, когда цикл находится в начале, и в этом случае он может сообщать об ошибке при повторном запуске. Подход Вэнь Чу не сообщает об ошибке, но результат не тот, который нам нужен.

Можно ли удалить с помощью Iterator?


@Test
public void testRemove6(){
    List<String> strings = new ArrayList<>();
    strings.add("a");
    strings.add("b");
    strings.add("c");
    strings.add("d");

    Iterator<String> iterator = strings.iterator();
    while (iterator.hasNext()){
        String next = iterator.next();
        strings.remove(next);
    }

    System.out.println(strings);
}
  • Ошибка: java.util.ConcurrentModificationException

Как правильно удалить

@Test
public void testRemove7(){
    List<String> strings = new ArrayList<>();
    strings.add("a");
    strings.add("b");
    strings.add("c");
    strings.add("d");

    Iterator<String> iterator = strings.iterator();
    while (iterator.hasNext()){
        String next = iterator.next();
        iterator.remove();
    }

    System.out.println(strings);
}