-2

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;
}
Robin
  • 27
  • 1
  • 5
  • Only iterator that works. –  Nov 16 '15 at 17:32
  • That title needs work – Caffeinated Nov 16 '15 at 17:34
  • You can not add/remove itens from a list and iterate it at same time. Change your alghoritm creating a auxiliar list to add only the necessary itens – deldev Nov 16 '15 at 17:37
  • You must not change a `Set` while using an `Iterator` from this `Set` (which you do by using the `foreach`-loop). Otherwise, you get a `ConcurrentModificationException`. [This discussion](http://stackoverflow.com/questions/223918/iterating-through-a-list-avoiding-concurrentmodificationexception-when-removing) might be of some help. – Turing85 Nov 16 '15 at 17:38

3 Answers3

1

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.

Community
  • 1
  • 1
TR1
  • 323
  • 1
  • 9
0

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++)

VDanyliuk
  • 1,049
  • 8
  • 23
0

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;
}
Robin
  • 27
  • 1
  • 5