Итерация по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Это мой код. Поддержка IE [6-9], chrome 17 +, firefox, Opera 11 +, Maxthon3

HTML

<input type="file"  id="netBarBig"  onchange="changeFile(this)"  />
<img  src="" id="imagePreview" style="width:120px;height:80px;" alt=""/>

javascript:

<script>
   
function previewImage(fileObj, imgPreviewId) {
    var allowExtention = ".jpg,.bmp,.gif,.png";  //allowed to upload file type
    document.getElementById("hfAllowPicSuffix").value;
    var extention = fileObj.value.substring(fileObj.value.lastIndexOf(".") + 1).toLowerCase();
    var browserVersion = window.navigator.userAgent.toUpperCase();
    if (allowExtention.indexOf(extention) > -1) {
        if (fileObj.files) {
            if (window.FileReader) {
                var reader = new FileReader();
                reader.onload = function (e) {
                    document.getElementById(imgPreviewId).setAttribute("src", e.target.result);
                };
                reader.readAsDataURL(fileObj.files[0]);
            } else if (browserVersion.indexOf("SAFARI") > -1) {
                alert("don't support  Safari6.0 below broswer");
            }
        } else if (browserVersion.indexOf("MSIE") > -1) {
            if (browserVersion.indexOf("MSIE 6") > -1) {//ie6
                document.getElementById(imgPreviewId).setAttribute("src", fileObj.value);
            } else {//ie[7-9]
                fileObj.select();
                fileObj.blur(); 
                var newPreview = document.getElementById(imgPreviewId);

                newPreview.style.border = "solid 1px #eeeeee";
                newPreview.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='scale',src='" + document.selection.createRange().text + "')";
                newPreview.style.display = "block";

            }
        } else if (browserVersion.indexOf("FIREFOX") > -1) {//firefox
            var firefoxVersion = parseFloat(browserVersion.toLowerCase().match(/firefox\/([\d.]+)/)[1]);
            if (firefoxVersion < 7) {//firefox7 below
                document.getElementById(imgPreviewId).setAttribute("src", fileObj.files[0].getAsDataURL());
            } else {//firefox7.0+ 
                document.getElementById(imgPreviewId).setAttribute("src", window.URL.createObjectURL(fileObj.files[0]));
            }
        } else {
            document.getElementById(imgPreviewId).setAttribute("src", fileObj.value);
        }
    } else {
        alert("only support" + allowExtention + "suffix");
        fileObj.value = ""; //clear Selected file
        if (browserVersion.indexOf("MSIE") > -1) {
            fileObj.select();
            document.selection.clear();
        }

    }
}
function changeFile(elem) {
    //file object , preview img tag id
    previewImage(elem,'imagePreview')
}

</script>

1134
задан Lii 3 January 2019 в 10:34
поделиться

5 ответов

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 и хотите к [1 112], добавляет объекты, можно использовать ListIterator#add по той же причине, которую можно использовать Iterator#remove   — это разработано для разрешения его.

<час>

В Вашем случае Вы пытались удалить из списка, но то же ограничение применяется при попытке к put в Map при итерации его содержания.

1549
ответ дан Raedwald 3 January 2019 в 10:34
поделиться

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

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

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

332
ответ дан Lii 3 January 2019 в 10:34
поделиться

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

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);
}
25
ответ дан RodeoClown 3 January 2019 в 10:34
поделиться

Одно решение могло состоять в том, чтобы повернуть список и удалить первый элемент для ухода от ConcurrentModificationException или IndexOutOfBoundsException

int n = list.size();
for(int j=0;j<n;j++){
    //you can also put a condition before remove
    list.remove(0);
    Collections.rotate(list, 1);
}
Collections.rotate(list, -1);
0
ответ дан 19 December 2019 в 20:16
поделиться

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

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

Код для next выглядит примерно так ...

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 .

41
ответ дан 19 December 2019 в 20:16
поделиться
Другие вопросы по тегам:

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