Как обрабатывать исключение параллелизма в Java при обновлении наборов? [Дубликат]

У нас были одни и те же проблемы с нашими подставными машинами jenkins (linux machine) и пробовали все варианты выше.

Единственное, что помогло, это установить эффект сжатия

chrome_options.add_argument ('- headless')

. Но когда мы исследовали дальше, заметили, что экран XVFB не работает 't начал свойство, и это вызывает эту ошибку. После того, как мы исправим экран XVFB, он решил проблему.

1037
задан Raedwald 28 March 2016 в 14:25
поделиться

21 ответ

Iterator.remove() безопасен, вы можете использовать его следующим образом:

List<String> list = new ArrayList<>();

// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
//     Iterator<String> iterator = list.iterator();
//     while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String string = iterator.next();
    if (string.isEmpty()) {
        // Remove the current element from the iterator and the list.
        iterator.remove();
    }
}

Обратите внимание, что Iterator.remove() является единственным безопасным способом изменять коллекцию во время итерации; поведение не определено, если базовая коллекция модифицируется каким-либо другим способом, пока выполняется итерация.

Источник: docs.oracle> Интерфейс коллекции


Аналогичным образом, если у вас есть ListIterator и вы хотите добавить элементы, вы можете использовать ListIterator#add , по той же причине вы можете использовать [f6 & mdash;] & NBSP; он предназначен для этого.

1472
ответ дан Pragati Singh 28 August 2018 в 16:06
поделиться

это может быть не лучшим образом, но для большинства небольших случаев это должно быть приемлемым:

"создать второй пустой массив и добавить только те, которые вы хотите keep "

Я не помню, где я это читал ... для справедливости я сделаю эту вики в надежде, что кто-то найдет ее или просто не заработает репутацию Я не заслуживаю.

-3
ответ дан ajax333221 28 August 2018 в 16:06
поделиться

С помощью Java 8 вы можете использовать новый removeIf метод . Применимо к вашему примеру:

Collection<Integer> coll = new ArrayList<Integer>();
//populate

coll.removeIf(i -> i.intValue() == 5);
157
ответ дан assylias 28 August 2018 в 16:06
поделиться
Collection<Integer> l = new ArrayList<Integer>();//Do the collection thing...

l.removeIf(i -> i == 5);      //iterates through the collection and removes every occurence of 5

Лямбда-выражения и методы сбора в Jdk 8 входят в Handy и добавляют некоторый синтаксический сахар

0
ответ дан Barnabas Ukwuani 28 August 2018 в 16:06
поделиться

С Коллекции Eclipse (ранее коллекции GS ) будет работать метод removeIf, определенный на MutableCollection :

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

С синтаксисом Java 8 Lambda это можно записать следующим образом:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);

Необходим вызов Predicates.cast(), потому что по умолчанию removeIf метод был добавлен на интерфейс java.util.Collection в Java 8.

Примечание: я являюсь коммиттером для коллекций Eclipse .

11
ответ дан bruno 28 August 2018 в 16:06
поделиться

Это работает:

Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
    if (iter.next().intValue() == 5) {
        iter.remove();
    }
}

Я предположил, что поскольку цикл foreach является синтаксическим сахаром для итерации, использование итератора не помогло бы ... но оно дает вам эту функциональность .remove().

321
ответ дан Christian Neverdal 28 August 2018 в 16:06
поделиться

В дополнение к @assylias answer вы также можете использовать новый поток api, если вы используете Java 8:

List<Integer> l = Arrays.asList(4, 5, 6);

static boolean condition(Integer i) {
    return i == 5;
}

static Predicate<Integer> predicate = YourClassName::condition;

l.stream()
    .filter(predicate.negate())
    .forEach(System.out::println);

Если вы инвертируете условие, решение становится еще более кратким, поскольку вам не нужно negate() предикат, что позволяет использовать только ссылку на метод:

List<Integer> l = Arrays.asList(4, 5, 6);

static boolean condition(Integer i) {
    return i != 5;    // <-- condition has been negated
}

l.stream()
    .filter(YourClassName::condition)
    .forEach(System.out::println);

Один из красотой этого является то, что поток лениво оценивается, т. е. операция filter() фактически не оценивается до тех пор, пока она не будет использована терминальной операцией, такой как forEach(). Подробнее об этом можно найти в учебнике для Oracle .

14
ответ дан Community 28 August 2018 в 16:06
поделиться
List<String> strings=new ArrayList<String>(){};

while(strings.size() > 0) {

 String str = strings.remove(0);
}
-1
ответ дан developer747 28 August 2018 в 16:06
поделиться

Поскольку вопрос уже ответил, то лучший способ - использовать метод удаления объекта итератора, я хотел бы перейти к особенностям места, где была выбрана ошибка "java.util.ConcurrentModificationException".

Каждый класс коллекции имеет частный класс, который реализует интерфейс Iterator и предоставляет такие методы, как next(), remove() и hasNext().

Следующий код выглядит примерно так:

public E next() {
    checkForComodification();
    try {
        E next = get(cursor);
        lastRet = cursor++;
        return next;
    } catch(IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
    }
}

Здесь метод checkForComodification реализован как

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

Итак, как вы можете видеть, если вы явно попытаетесь удалить элемент из коллекции. Это приводит к тому, что modCount отличается от expectedModCount, что приводит к исключению ConcurrentModificationException.

40
ответ дан i_am_zero 28 August 2018 в 16:06
поделиться

Лучшим способом (рекомендуется) является использование пакета java.util.Concurrent. Используя этот пакет, вы можете легко избежать этого исключения. см. Модифицированный код

public static void main(String[] args) {
        Collection<Integer> l = new CopyOnWriteArrayList<Integer>();

        for (int i=0; i < 10; ++i) {
            l.add(new Integer(4));
            l.add(new Integer(5));
            l.add(new Integer(6));
        }

        for (Integer i : l) {
            if (i.intValue() == 5) {
                l.remove(i);
            }
        }

        System.out.println(l);
    }
1
ответ дан jagdish khetre 28 August 2018 в 16:06
поделиться

A ListIterator позволяет добавлять или удалять элементы в списке. Предположим, у вас есть список объектов Car:

List<Car> cars = ArrayList<>();
// add cars here...

for (ListIterator<Car> carIterator = cars.listIterator();  carIterator.hasNext(); )
{
   if (<some-condition>)
   { 
      carIterator().remove()
   }
   else if (<some-other-condition>)
   { 
      carIterator().add(aNewCar);
   }
}
1
ответ дан james.garriss 28 August 2018 в 16:06
поделиться

Люди утверждают, что нельзя удалить из коллекции, которая повторяется в цикле foreach. Я просто хотел указать, что это технически неверно и точно описывает (я знаю, что вопрос OP настолько продвинут, чтобы избежать этого, чтобы понять это) код, лежащий в основе этого предположения:

    for (TouchableObj obj : untouchedSet) {  // <--- This is where ConcurrentModificationException strikes
        if (obj.isTouched()) {
            untouchedSet.remove(obj);
            touchedSt.add(obj);
            break;  // this is key to avoiding returning to the foreach
        }
    }

Не исключено, что вы не сможете удалить из итерированного Colletion, а затем продолжить, после чего продолжить. Следовательно, break в коде выше.

Извиняется, если этот ответ является несколько специализированным прецедентом и более подходит для исходного потока , из которого я пришел сюда, отмеченный как дубликат (несмотря на то, что этот поток выглядит более нюансированным) этого и заблокирован.

4
ответ дан John 28 August 2018 в 16:06
поделиться

В таких случаях общий трюк (был?) для возврата назад:

for(int i = l.size() - 1; i >= 0; i --) {
  if (l.get(i) == 5) {
    l.remove(i);
  }
}

Тем не менее, я более чем счастлив, что у вас есть лучшие способы в Java 8, например. removeIf или filter в потоках.

17
ответ дан Landei 28 August 2018 в 16:06
поделиться

С традиционным для цикла

ArrayList<String> myArray = new ArrayList<>();

   for (int i = 0; i < myArray.size(); ) {
        String text = myArray.get(i);
        if (someCondition(text))
             myArray.remove(i);
        else 
             i++;
      }
6
ответ дан Lluis Felisart 28 August 2018 в 16:06
поделиться

Вы можете перебирать список, используя for-loop, и вам нужно вызвать list.remove (0). Вам нужно с жестким кодом индексировать индексный параметр remove с нулем. См. Также этот ответ :

List<Integer> list = new ArrayList<Integer>();

list.add(1);
list.add(2);
list.add(3);
list.add(4);
int list_size = list.size();
for (int i = 0; i < list_size; i++) {
    list.remove(0);
}
-1
ответ дан Markus Pscheidt 28 August 2018 в 16:06
поделиться

В случае ArrayList: remove (int index) - если (индекс - позиция последнего элемента), он избегает без System.arraycopy() и не занимает времени для этого.

Время arraycopy увеличивается, если (индекс уменьшается), кстати, элементы списка также уменьшаются!

лучший эффективный способ удаления - удаление его элементов в порядке убывания: while(list.size()>0)list.remove(list.size()-1); // принимает O (1) while(list.size()>0)list.remove(0); // принимает O (факториал ( n))

//region prepare data
ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
Random rdm = new Random();
long millis;
for (int i = 0; i < 100000; i++) {
    Integer integer = rdm.nextInt();
    ints.add(integer);
}
ArrayList<Integer> intsForIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsDescIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsIterator = new ArrayList<Integer>(ints);
//endregion

// region for index
millis = System.currentTimeMillis();
for (int i = 0; i < intsForIndex.size(); i++) 
   if (intsForIndex.get(i) % 2 == 0) intsForIndex.remove(i--);
System.out.println(System.currentTimeMillis() - millis);
// endregion

// region for index desc
millis = System.currentTimeMillis();
for (int i = intsDescIndex.size() - 1; i >= 0; i--) 
   if (intsDescIndex.get(i) % 2 == 0) intsDescIndex.remove(i);
System.out.println(System.currentTimeMillis() - millis);
//endregion

// region iterator
millis = System.currentTimeMillis();
for (Iterator<Integer> iterator = intsIterator.iterator(); iterator.hasNext(); )
    if (iterator.next() % 2 == 0) iterator.remove();
System.out.println(System.currentTimeMillis() - millis);
//endregion
  • для индексной петли: 1090 мс
  • для индекса desc: 519 мсек --- лучший
  • для итератора: 1043 мсек
0
ответ дан Nurlan 28 August 2018 в 16:06
поделиться

Сделать копию существующего списка и перебрать новую копию.

for (String str : new ArrayList<String>(listOfStr))     
{
    listOfStr.remove(/* object reference or index */);
}
6
ответ дан Priyank Doshi 28 August 2018 в 16:06
поделиться

Вы можете либо использовать итератор прямо так, как вы упомянули, либо сохранить вторую коллекцию и добавить каждый элемент, который хотите удалить, в новую коллекцию, а затем удалитьAll в конце. Это позволяет вам использовать безопасность типа для каждого цикла за счет увеличения использования памяти и времени процессора (не должно быть огромной проблемой, если у вас нет действительно больших списков или действительно старого компьютера)

public static void main(String[] args)
{
    Collection<Integer> l = new ArrayList<Integer>();
    Collection<Integer> itemsToRemove = new ArrayList<Integer>();
    for (int i=0; i < 10; ++i) {
    l.add(new Integer(4));
    l.add(new Integer(5));
    l.add(new Integer(6));
    }
    for (Integer i : l)
    {
        if (i.intValue() == 5)
            itemsToRemove.add(i);
    }

    l.removeAll(itemsToRemove);
    System.out.println(l);
}
22
ответ дан RodeoClown 28 August 2018 в 16:06
поделиться
for (Integer i : l)
{
    if (i.intValue() == 5){
            itemsToRemove.add(i);
            break;
    }
}

Ловушка - это удаление элемента из списка, если вы пропустите внутренний вызов iterator.next (). он все еще работает! Хотя я и не предлагаю писать такой код, он помогает понять концепцию: -)

Cheers!

0
ответ дан Srinivasan Thoyyeti 28 August 2018 в 16:06
поделиться

У меня есть предложение по указанной выше проблеме. Нет необходимости в дополнительном списке или дополнительном времени. Пожалуйста, найдите пример, который будет делать одни и те же вещи, но по-другому.

//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
    Object r = list.get(index);
    if( state ) {
        list.remove(index);
        index = 0;
        continue;
    }
    index += 1;
}

Это позволит избежать исключения параллелизма.

0
ответ дан svick 28 August 2018 в 16:06
поделиться

ConcurrentHashMap или ConcurrentLinkedQueue или ConcurrentSkipListMap может быть другой опцией, потому что они никогда не будут бросать любое ConcurrentModificationException, даже если вы удалите или добавите элемент.

0
ответ дан Yessy 28 August 2018 в 16:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: