spring 使用迭代器时出现并发修改异常

idv4meu8  于 2022-10-30  发布在  Spring
关注(0)|答案(1)|浏览(855)

我遇到了一个问题,这个集合上的迭代器。这是一个小项目,我用spring初始化程序创建的。
我使用Tomcat的Sping Boot 。之前我使用了for循环,然后我在这里看到了这个答案Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop,并试图将第一个答案适应我的情况。
唯一的问题是,我必须在删除之前从双向一对多、多对一关系中分离两个实体Parent和Child。即使我使用迭代器,我仍然会得到这个错误。

@PostMapping("/savecart")
    public ResponseEntity<String> saveCartToDb(@RequestBody Set<CartProduct> cartProductList, Principal principal) {
        User logedInUser = userService.findUserByUsername(principal.getName()).get();

        Set<CartProduct> cartItemList = logedInUser.getCartProduct();

        for (CartProduct cartProduct : cartProductList) {
            cartProduct.setUser(logedInUser);
        }
        userService.saveNewUser(logedInUser);
        log.info("In saveCartToDb()");
        if (cartItemList.isEmpty()) {
            logedInUser.setCartProduct(cartProductList);
            userService.saveNewUser(logedInUser);
        } else {
            for (Iterator<CartProduct> iterator = cartItemList.iterator(); iterator.hasNext();) {
                CartProduct cartItem = iterator.next();
                if (cartItem != null) {
                    // Remove the current element from the iterator and the list.
                    cartItem.dismissParent();
                    logedInUser.dismissChild(cartItem);
                    iterator.remove();
                    userService.saveNewUser(logedInUser);

                }
            }
//            for(CartProduct cartItem : cartItemList){
//                cartItem.dismissParent();
//                logedInUser.dismissChild(cartItem);
//                userService.saveNewUser(logedInUser);
//            }
            cartProductService.deleteAllProductIds();
            for (CartProduct cartProduct : cartProductList) {
                cartProduct.setUser(logedInUser);
            }
            logedInUser.setCartProduct(cartProductList);
            userService.saveNewUser(logedInUser);
        }
        return ResponseEntity.ok().body(cartProductList.toString());
    }

我用来解耦的方法
第一个
有没有一种方法可以修改迭代器,不再收到这个错误?或者有没有一个更好的解决方案,与迭代器?

2vuwiymt

2vuwiymt1#

根据你的异常

java.util.ConcurrentModificationException: null
    at java.base/java.util.HashMap$HashIterator.remove(HashMap.java:1611) [na:na]

因此,您使用了HashMap,并且收到了ConcurrentModificationException
但是,等等,你的代码中没有任何HashMap,对吗?
您有cartItemList.iterator(),而cartItemList宣告为Set<CartProduct>。您所提供的实作也会是HashSet
但是**HashSet是使用HashMapjava在后台实现的。因此,您遇到的错误提到了HashMap
documentation开始
公共类
并发修改异常**扩展运行时异常
当不允许对对象进行并发修改时,检测到此类修改的方法可能会引发此异常。例如,通常不允许一个线程修改Collection,而另一个线程正在对其进行迭代。通常,在这些情况下,迭代的结果是未定义的。一些迭代器实现(包括JRE提供的所有通用集合实现)可以选择抛出此异常。执行此操作的迭代器被称为故障快速迭代器,因为它们快速而干净地失败,而不是冒着在未来的不确定时间的任意的、非确定性的行为的风险。

请注意,这个例外状况并不一定表示对象已由不同的执行绪同时修改。如果单一执行绪发出一系列违反对象契约的方法叫用,对象可能会掷回这个例外状况。例如,如果执行绪在使用故障快速迭代器(Fail-fast Iterator)反覆运算集合时,直接修改集合,迭代器将抛出此异常

HashMapHashSet提供了一个故障快速迭代器,这意味着在迭代过程中不允许修改集合。
为了解决您的问题,您应该避免在迭代期间修改集合。
所以下面的代码块

for (Iterator<CartProduct> iterator = cartItemList.iterator(); iterator.hasNext();) {
                CartProduct cartItem = iterator.next();
                if (cartItem != null) {
                    // Remove the current element from the iterator and the list.
                    cartItem.dismissParent();
                    logedInUser.dismissChild(cartItem);
                    iterator.remove();
                    userService.saveNewUser(logedInUser);

                }
            }

可以重写为

List<CartProduct> toBeRemoved = new ArrayList(); <-----------
for (Iterator<CartProduct> iterator = cartItemList.iterator(); iterator.hasNext();) {
                CartProduct cartItem = iterator.next();
                if (cartItem != null) {
                    // Remove the current element from the iterator and the list.
                    cartItem.dismissParent();
                    logedInUser.dismissChild(cartItem);
                    toBeRemoved.add(cartItem);  <---------------
                    userService.saveNewUser(logedInUser);

                }
            }
cartItemList.removeAll(toBeRemoved); <--------

因此,您只需在迭代过程中收集所有需要删除的元素,并仅在迭代后调用删除操作。

相关问题