简体   繁体   中英

Java iteration in iteration

I need to iterate over an object set and find all equal cost-categories and join them together. I tried to put a while-loop into another while-loop. However this doesn't work; I always get the ConcurrentModificationException. Why do I still get this?

How to make this work, so that it works just like two nested for-loops

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;
}

The troublesome line is the below -

  expenseItemsIteratorInner.remove();

You can't modify a Set (or any Collection object) in an inner loop as this will change the structure of the Set . For example, say if you want to iterate over each element of a Collection that has a size of 10 - so your foreach loop would run 10 times. But in the 5th run of the loop you go into another inner loop and try to delete/modify the current item (at the 5th position) - your foreach loop wouldn't be able to proceed because the outer loop has locked the Set . More details here .

What you could do is store the items you want to delete in a temporary Set and then delete them later. Something like (not tested but I think will give you the idea) -

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.

An example of how to remove items in a Set can be found here .

When You use foreach statement Java behind the scene use iterator. So You have two iterators and when You delete element with one of this iterators another throws this exception. You can use regular loop like for(int i = 0; i <= set.size(); i++)

Thanks for your inputs! Without them I would probably still be busy finding a solution. I just tranfered the expenseItem to an array-list:

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM