Servlet中的java.util.ConcurrentModificationException

Servlet中的java.util.ConcurrentModificationException,java,servlets,arraylist,collections,iterator,Java,Servlets,Arraylist,Collections,Iterator,编辑:我理解我的错误。我不知道为什么,但我在想,在前面的items.add(p)之后被执行,它是从循环的中发出的。我通过添加一个break 关于这个异常的其他问题并没有帮助我找到解决方案 我有一个Servlet,当我从另一个页面向购物车中添加一个项目时会调用它 我有一个ArrayList,我遍历列表,检查列表中是否已经有我试图添加的相同产品。如果它已经在那里,我会更新它的数量,否则我会在列表中添加新产品 如果总是添加相同的产品,那么一切都很好,当我添加不同的产品时会出现异常。所以我认为代码中的问

编辑:我理解我的错误。我不知道为什么,但我在想,在
前面的items.add(p)之后被执行,它是从循环的
中发出的。我通过添加一个
break

关于这个异常的其他问题并没有帮助我找到解决方案

我有一个
Servlet
,当我从另一个页面向购物车中添加一个项目时会调用它

我有一个
ArrayList
,我遍历列表,检查列表中是否已经有我试图添加的相同产品。如果它已经在那里,我会更新它的数量,否则我会在列表中添加新产品

如果总是添加相同的产品,那么一切都很好,当我添加不同的产品时会出现异常。所以我认为代码中的问题是在
else
(用“This”注释)之后,因为如果产品不同,它就会执行

@WebServlet(name = "AddCart", urlPatterns = {"/AddCart"})
public class AddCart extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        ArrayList<Product> previousItems = (ArrayList<Product>) session.getAttribute("previousItems");
        Product p = (Product) session.getAttribute("currentProduct");
        if (previousItems == null) {
            previousItems = new ArrayList<Product>();
        }

            if (p != null) {
                if (previousItems.size()>0) {
                    for (Product p1 : previousItems) {
                        if (p1.getId() == p.getId()) {
                            p1.addQuantity();
                        } else { //This
                            previousItems.add(p);
                        }
                    }
                } else {
                    previousItems.add(p);
                }
            }

        session.setAttribute("previousItems", previousItems);
        response.sendRedirect("cart.jsp");
    }
}
@WebServlet(name=“AddCart”,urlPatterns={”/AddCart})
公共类AddCart扩展了HttpServlet{
@凌驾
受保护的void doGet(HttpServletRequest请求,HttpServletResponse响应)抛出ServletException,IOException{
HttpSession session=request.getSession();
ArrayList previousItems=(ArrayList)session.getAttribute(“previousItems”);
productp=(Product)session.getAttribute(“currentProduct”);
如果(以前的项==null){
previousItems=新的ArrayList();
}
如果(p!=null){
如果(previousItems.size()>0){
对于(产品p1:以前的项目){
如果(p1.getId()==p.getId()){
p1.添加数量();
}否则{//
增加(p);
}
}
}否则{
增加(p);
}
}
session.setAttribute(“previousItems”,previousItems);
sendRedirect(“cart.jsp”);
}
}
我还试图删除
synchronized
相同的异常

这是HTTP状态500–内部服务器错误

java.util.ConcurrentModificationException

for (Product p1 : previousItems) {
    previousItems.add(p); //you cant update the previousItems list here
}
java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) java.util.ArrayList$Itr.next(ArrayList.java:851) servlet.AddCart.doGet(AddCart.java:36) javaservlet.http.HttpServlet.service(HttpServlet.java:635) javaservlet.http.HttpServlet.service(HttpServlet.java:742) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)


当您修改
for
循环的
内部的
ArrayList
时,会出现此异常。在内部,
for
循环使用
Iterator
,不允许在迭代期间修改非线程安全集合。你们可以阅读这篇文章来了解更多

但是,我建议您按以下方式更改逻辑:

if (p != null) {
  // Check if previousItems already contains the product
  if (!previousItems.contains(p)) {
    // If it doesn't, add the product
    previousItems.add(p);
  }
}

当您修改
for
循环的
内部的
ArrayList
时,会出现此异常。在内部,
for
循环使用
Iterator
,不允许在迭代期间修改非线程安全集合。你们可以阅读这篇文章来了解更多

但是,我建议您按以下方式更改逻辑:

if (p != null) {
  // Check if previousItems already contains the product
  if (!previousItems.contains(p)) {
    // If it doesn't, add the product
    previousItems.add(p);
  }
}

不能将项目添加到使用增强for循环迭代的列表中。这是因为您正在修改列表的内部状态;虽然可以处理这一点,但大多数迭代器实现并不处理底层集合的状态更改,以便对绝大多数用例保持简单

与此相反:

for (Product p1 : previousItems) {
    previousItems.add(p); // Simplified
}
如果希望
p
在之后进入列表,请将其放入另一个列表中,然后在迭代后添加该列表:

List<Product> other = new ArrayList<>();
for (Product p1 : previousItems) {
    other.add(p);
}
previousItems.addAll(other);
List other=new ArrayList();
对于(产品p1:以前的项目){
其他.添加(p);
}
以前的项目。添加所有(其他);

您不能将项目添加到使用增强for循环迭代的列表中。这是因为您正在修改列表的内部状态;虽然可以处理这一点,但大多数迭代器实现并不处理底层集合的状态更改,以便对绝大多数用例保持简单

与此相反:

for (Product p1 : previousItems) {
    previousItems.add(p); // Simplified
}
如果希望
p
在之后进入列表,请将其放入另一个列表中,然后在迭代后添加该列表:

List<Product> other = new ArrayList<>();
for (Product p1 : previousItems) {
    other.add(p);
}
previousItems.addAll(other);
List other=new ArrayList();
对于(产品p1:以前的项目){
其他.添加(p);
}
以前的项目。添加所有(其他);

无法更新正在迭代的列表,这将导致ConcurrentModificationException

for (Product p1 : previousItems) {
    previousItems.add(p); //you cant update the previousItems list here
}
相反,您可以做的是:

ArrayList<Product> auxList = new ArrayList<>();
for (Product p1 : previousItems) {
    //...
    //else...
        auxList.add(p);
}

无法更新正在迭代的列表,这将导致ConcurrentModificationException

for (Product p1 : previousItems) {
    previousItems.add(p); //you cant update the previousItems list here
}
相反,您可以做的是:

ArrayList<Product> auxList = new ArrayList<>();
for (Product p1 : previousItems) {
    //...
    //else...
        auxList.add(p);
}

如果您只想避免ConcurrentModificationException,请使用CopyOnWriteArrayList而不是ArrayList。

如果您只想避免ConcurrentModificationException,请使用CopyOnWriteArrayList而不是ArrayList。

尝试谷歌搜索该错误消息?是的,但我没有帮助。我已经试过ListIterators了。我已经试了一个多小时来解决这个问题。我知道问题出在迭代器上,但当我调用Servlet时,它不是又设置为列表的开头吗?它会告诉你在迭代列表时不改变列表的一些事情……哦,现在我明白问题了。我不知道为什么我在尝试谷歌搜索错误信息之前没有注意到它?是的,但我没有帮助。我已经试过ListIterators了。我已经试了一个多小时来解决这个问题。我知道问题出在迭代器上,但当我调用Servlet时,它不是又设置为列表的开头吗?它会告诉你在迭代列表时不改变列表的一些事情……哦,现在我明白问题了。我不知道为什么我以前没有注意到是的,这很容易。我在
previ之后添加了一个
break