0

EDIT its worked

        group.getUsers().forEach(user -> {
        user.removeGroup(group);
        privilegeRepository.findAll().stream().
                filter(privilege -> privilege.getName().startsWith(slugname.toUpperCase()))
                .forEach(privilege -> {
            user.removePrivilege(privilege);
            privilegeRepository.delete(privilege);
        });
    });

I have nested for-loops and I want to replace that for-loops with a forEach:

for (User user : group.getUsers()) {
     user.removeGroup(group);

     for(Privilege privilege : user.getPrivileges()){

         if (privilege.getName().startsWith(slugname.toUpperCase())){
             user.removePrivilege(privilege);
             privilegeRepository.delete(privilege);
         }
     }
}

to

group.getUsers().forEach(user -> {

     user.removeGroup(group);

     user.getPrivileges().stream().filter(privilege -> privilege.getName().startsWith(slugname.toUpperCase()))
          .forEach(privilege -> {
              user.removePrivilege(privilege);
              privilegeRepository.delete(privilege);
          });
});

And it throws a exception:

java.util.ConcurrentModificationException

zblash
  • 133
  • 2
  • 11
  • the complete stack trace would be useful, so we can see what line throw the exception – NickJ Feb 26 '19 at 08:28
  • 1
    `user.getPrivileges()` vs `privilegeRepository.findAll()`: doesn't look like the two are doing the same thing – ernest_k Feb 26 '19 at 08:29
  • 2
    Instead of using streams here it might make more sense to use an old fashioned iterator which you can call `remove()` on to get the privilege removed from the user's privileges. – Thomas Feb 26 '19 at 08:31
  • 1
    You cannot call `user.removePrivilege` while iterating over `user.getPrivileges`. You need to make a snapshot copy to iterate over. – Thilo Feb 26 '19 at 08:32
  • So in this case no need replace for-loops with a forEach ? – zblash Feb 26 '19 at 08:43
  • 1
    It is interesting why you do not get `java.util.ConcurrentModificationException` in the first example (with the nested for-loops). I think `user.removePrivilege(privilege);` still can make modification on the collection that you are iterating in the same time. – Level_Up Feb 26 '19 at 08:52
  • I don't know why but I don't get error first example – zblash Feb 26 '19 at 08:56

1 Answers1

0

It is what it says. In the loop, you are modifying the array you are looping through, which is not allowed in Java foreach loops.

I'd suggest you create a temporary array in the outer foreach loop (where you loop the users) for the privileges and delete the items from that array, instead of the user's privilege array. So instead of user.removePrivilege(privilege); you should use something like temp.remove(privilege).

After the inner loop, you can clear the user's privilege array and add the items in the temporary array.

László Stahorszki
  • 1,102
  • 7
  • 23
  • So in this case no need replace for-loops with a forEach ? – zblash Feb 26 '19 at 08:43
  • no, you can keep the forEach – László Stahorszki Feb 26 '19 at 09:09
  • 2
    @zblash the for-loops have exactly the same problem. The iteration policy does not change when you use a Stream, so you’re using a collection not allowing modifications while iterating and it’s a pure coincidence if you did not hit the exception previously. – Holger Feb 26 '19 at 10:16