【问题标题】:Java iteration in iteration迭代中的Java迭代
【发布时间】:2016-02-17 21:30:45
【问题描述】:

我需要遍历一个对象集并找到所有相等的成本类别并将它们连接在一起。我试图将一个while循环放入另一个while循环中。但是,这不起作用;我总是得到 ConcurrentModificationException。为什么我还是会得到这个?

如何使它工作,使它像两个嵌套的for循环一样工作

public Set<ExpenseItem> getConsolidatedExpenseitems(String expenseUid) {
    Expense expense = getByUid(expenseUid);

    Set<ExpenseItem> expenseItems = expense.getExpenseItems();
    Set<ExpenseItem> expenseItemsInner = expense.getExpenseItems();

    for(ExpenseItem e : expenseItems) { // ConcurrentModificationException
        Iterator<ExpenseItem> expenseItemsIteratorInner = expenseItems.iterator();

        expenseItemsIteratorInner = expenseItemsInner.iterator();
        while(expenseItemsIteratorInner.hasNext()) {
            ExpenseItem eInner = expenseItemsIteratorInner.next();
            if(e != null) {
                if(eInner.getCostCategory().equals(e.getCostCategory())) {
                    System.out.println(e.getCalculatedAmount());
                    System.out.println(eInner.getCalculatedAmount());
                    System.out.println("---");
                    expenseItemsIteratorInner.remove();
                }
            }
        }
    }

    return null;
}

【问题讨论】:

  • 唯一有效的迭代器。
  • 那个标题需要修改
  • 您不能在列表中添加/删除元素并同时对其进行迭代。更改创建辅助列表的算法以仅添加必要的项目
  • 在使用 Iterator 从这个 Set 时,您不能更改 Set(您可以使用 foreach-loop 执行此操作)。否则,你会得到一个ConcurrentModificationExceptionThis discussion 可能会有所帮助。

标签: java loops


【解决方案1】:

感谢您的意见!没有他们,我可能仍会忙于寻找解决方案。我只是将费用项转移到数组列表中:

public ArrayList<ExpenseItemPdfDto> getConsolidatedExpenseItems(String expenseUid) {
    Expense expense = getByUid(expenseUid);
    Set<ExpenseItem> expenseItems = expense.getExpenseItems();
    Iterator<ExpenseItem> expenseItemsIterator = expenseItems.iterator();
    ArrayList<ExpenseItemPdfDto> expenseItemsList = new ArrayList<ExpenseItemPdfDto>();

    while(expenseItemsIterator.hasNext()) {
        ExpenseItem eInner = expenseItemsIterator.next();

        ExpenseItemPdfDto dto = new ExpenseItemPdfDto();
        dto.setAccountNumber(eInner.getCostCategory().getAccountNumber());
        dto.setCostCategoryName(eInner.getCostCategory().getName().getDe());
        dto.setOriginalAmount(eInner.getOriginalAmount());
        dto.setProject(eInner.getProject());
        expenseItemsList.add(dto);
    }

    double amount = 0;
    for(int i=0;i<expenseItemsList.size();i++) {
        if(expenseItemsList.get(i) != null) {
            for(int j=0;j<expenseItemsList.size();j++) {
                if(expenseItemsList.get(j) != null) {
                    if(expenseItemsList.get(i).getAccountNumber() == expenseItemsList.get(j).getAccountNumber()) {
                        if(i != j) {
                            amount = expenseItemsList.get(i).getOriginalAmount();
                            amount += expenseItemsList.get(j).getOriginalAmount();
                            expenseItemsList.get(i).setOriginalAmount(amount);
                            expenseItemsList.remove(j);
                        }
                    }
                }
            }
        }
    }

    return expenseItemsList;
}

【讨论】:

    【解决方案2】:

    麻烦的线是下面 -

      expenseItemsIteratorInner.remove();
    

    您不能在内部循环中修改Set(或任何Collection 对象),因为这会改变Set 的结构。例如,假设您要遍历大小为 10 的 Collection 的每个元素 - 那么您的 foreach 循环将运行 10 次。但是在循环的第 5 次运行中,您进入另一个内部循环并尝试删除/修改当前项目(在第 5 个位置)-您的 foreach 循环将无法继续,因为外部循环已锁定 @ 987654330@。更多详情here.

    您可以做的是将要删除的项目存储在临时Set 中,然后再将其删除。类似的东西(未经测试,但我认为会给你这个想法) -

    Set<ExpenseItem> toDelete = new HashSet<>();
    while(expenseItemsIteratorInner.hasNext()) {
        ExpenseItem eInner = expenseItemsIteratorInner.next();
        if(e != null) {
            if(eInner.getCostCategory().equals(e.getCostCategory())) {
                    ...
    
            toDelete.add(expenseItemsIteratorInner.next());
        }
      }
    }
    
    //Code to remove items in the Set toDelete goes here.
    

    可以在here 中找到如何删除Set 中的项目的示例。

    【讨论】:

      【解决方案3】:

      当你在后台使用 foreach 语句时,Java 使用迭代器。因此,您有两个迭代器,当您使用其中一个迭代器删除元素时,另一个会引发此异常。 您可以使用常规循环,例如 for(int i = 0; i &lt;= set.size(); i++)

      【讨论】:

      • 那是评论而不是答案。
      • 解释为什么会出现Exception 会有所帮助。
      • 当你使用 foreach 语句时 Java 在后台使用迭代器。因此,您有两个迭代器,当您使用其中一个迭代器删除元素时,另一个会引发此异常。
      猜你喜欢
      • 1970-01-01
      • 2012-03-23
      • 2014-03-25
      • 1970-01-01
      • 2010-11-25
      • 2017-06-12
      • 2011-02-22
      • 2010-10-28
      • 2020-08-22
      相关资源
      最近更新 更多