【问题标题】:java.util.ConcurrentModificationException with custom ArrayList带有自定义 ArrayList 的 java.util.ConcurrentModificationException
【发布时间】:2017-01-24 07:51:22
【问题描述】:

我当然知道这个错误是什么意思,但我不知道如何删除它。 现在我正在尝试

 private void removeFriendFromList() {
    List<Friend> copy = new ArrayList<Friend>(globalSearchFriends);
    for (Friend friend : globalSearchFriends) {
        if (friend.equals(remove)) {
            copy.remove(friend);
        }
    }
}

但这不起作用。 这是我的全局列表

 private List<Friend> globalSearchFriends = new ArrayList<>();

我也在尝试迭代,但没有成功,或者我做错了什么。

我还需要在这里使用它:我在 api 中搜索朋友,这就像我在 EditText 中输入文本然后在我的适配器中看到该用户时一样,但这仅适用于少数成员,总是当我像“andrew”一样搜索然后我搜索“youko”我得到了错误。

private void serachFriend(final String query) {

    etGlobalSearch.addTextChangedListener(new TextWatcherAdapter() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            FindFriend request = new FindFriend();
            request.query = query;
            request.query = s.toString().toLowerCase().trim();
            backend.findFriend(request).enqueue(new Callback<ResponseFindFriend>() {
                @Override
                public void onResponse(Call<ResponseFindFriend> call, Response<ResponseFindFriend> response) {
                    synchronized (globalSearchFriends) {
                        globalSearchFriends.clear();
                        removeFriendFromList();
                        try {
                            if (response == null)
                                throw new Exception();
                            if (!response.isSuccessful())
                                throw new Exception();
                            if (response.body() == null)
                                throw new Exception();
                            if (response.body().results == null)
                                throw new Exception();
                            globalSearchFriends = response.body().results;
                        } catch (Exception e) {
                            Log.d("Blad", "sobie");
                        } finally {
                            gatherResults();
                        }
                    }
                }

                @Override
                public void onFailure(Call<ResponseFindFriend> call, Throwable t) {
                    synchronized (globalSearchFriends) {
                        globalSearchFriends.clear();
                        removeFriendFromList();
                        gatherResults();
                    }
                }
            });
        }
    });
}

private void removeFriendFromList() {
    List<Friend> copy = new ArrayList<Friend>(globalSearchFriends);
    for (Friend friend : globalSearchFriends) {
        if (friend.equals(remove)) {
            copy.remove(friend);
        }
    }
}

private void gatherResults() {
    removeFriendFromList();
    for (Friend f : globalSearchFriends)
        globalSearchFriends.add(f);
    findedFriendsAdapter.setFriendList(globalSearchFriends);
}

任何相关的帮助,祝你有美好的一天! :)

编辑 我在这个案例中遇到了错误。

java.util.ConcurrentModificationException
   for (Friend f : globalSearchFriends)
        globalSearchFriends.add(f);
    findedFriendsAdapter.setFriendList(globalSearchFriends);

在日志上我有:

   at java.util.ArrayList$ArrayListIterator.next

【问题讨论】:

  • 在迭代列表的同时修改列表时应该使用迭代器。
  • 请提供 real minimal reproducible example 和匹配的堆栈跟踪。迭代一个列表时,从另一个列表中删除元素应该可以正常工作。所以我假设你的代码只显示了部分事实。并且只是为了记录:您在 Friends 类中是否覆盖等于?
  • @jitinsharma 他没有在迭代时修改列表。他正在操纵该列表的副本
  • globalSearchFriends.clear(); removeFriendFromList(); 列表已经为空,您正在对其进行迭代。
  • 我告诉过你。请阅读minimal reproducible example!还有:堆栈跟踪!

标签: java android arraylist


【解决方案1】:

这听起来很可疑:

for (Friend f : globalSearchFriends)
    globalSearchFriends.add(f);

您尝试在迭代时将globalSearchFriends 的内容添加到自身,这是ArrayList 不允许的,因此它会导致ConcurrentModificationException。实际上ArrayList#iterator() 返回一个fail-fast iterator,这意味着:

如果列表被结构修改在迭代器之后的任何时间 以任何方式创建,除了通过迭代器自己的removeadd 方法,迭代器将抛出一个ConcurrentModificationException

这听起来不像是正常/预期的行为,但如果您真的想复制列表的内容,只需使用 addAll(Collection&lt;? extends E&gt; c) 而不是作为下一个迭代:

globalSearchFriends.addAll(globalSearchFriends);
// or globalSearchFriends.addAll(new ArrayList<>(globalSearchFriends)); for safety
findedFriendsAdapter.setFriendList(globalSearchFriends);

注意:ArrayList 不是线程安全的,因此当且仅当列表未共享或受显式或内在锁保护时,请确保在列表上调用 addAll(Collection&lt;? extends E&gt; c)否则你会得到不可预知的行为。

【讨论】:

  • AddAll 不能保证工作:“如果指定的集合是这个列表,这个调用的行为是未定义的,并且这个列表是非空的。”
  • @Joni 当然,因为ArrayList 不是线程安全的,但这里不是问题,因为它是在同步块中完成的
  • 是的,这对我有帮助。问题是我对所有内容都使用一个列表,现在当我为 findFrieds 创建新列表时,我现在遇到了问题。谢谢你帮了我很多:)
  • @Joni 我为此添加了一个 NB
  • 阅读 addAll 方法的文档:线程和锁与它无关。 list.addAll(list) 不能保证有效,即使在当前实现中它确实有效。 (也许这是一个文档错误?)
【解决方案2】:

CopyOnWrite Collection 怎么样?

public static void main(String[] args) {
    CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList();
    for (int i = 0; i < 10; i++) {
        list.add(i);
    }

    for (Integer num : list) {
        if (num % 2 == 0) {
            list.add(num * 100);
        }
    }
    System.out.println("list = " + list);
}

输出 列表 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 200, 400, 600, 800]

【讨论】:

    【解决方案3】:

    试试下面

       private void removeFriendFromList() {
         List<Friend> copy = new ArrayList<Friend>(globalSearchFriends);
         Friend targetToRemove = null;
         for (Friend friend : globalSearchFriends) {
           if (friend.equals(remove)) {
             targetToRemove = friend;
           }
         }
         if (targetToRemove != null) {
           copy.remove(targetToRemove);
         }
       }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-05
      • 2014-12-13
      • 2013-12-10
      • 2014-04-08
      • 2013-06-02
      • 1970-01-01
      • 2012-11-02
      • 1970-01-01
      相关资源
      最近更新 更多