So, I am running into a bit of a snag with my code and I'm not sure why, or how to get around it. I am writing a method that will take a list of objects and filter it based around some rules. After applying all of the rules, if the list is still over a certain size I need to randomly select items from a specific sublist then and discard the rest. The problem I am running into comes from this block of code:
List<Group> filteredList = groupList.subList(0, firstMatch);
if(filteredList.size() < MAX_NUM_RETURNED){
//This sub list is where I need to pull random items from
List<Group> subList = new ArrayList<Group>();
subList = groupList.subList(firstMatch, lastMatch);
Random rand = new Random();
while(filteredList.size() < MAX_NUM_RETURNED){
int randPos = rand.nextInt(subList .size());
//remove a random group from the sublist and add it to the filtered list
filteredList.add(subList.remove(randPos));
}
}
The filteredList
starts with 0 - n groups, and if its size is less than the maximum random groups from a subset are added until it hits that number.
The problem is that when the filteredList.add(subList.remove(randPos));
line is called I get a ConcurrentModificationException
error and the program halts.
I've looked up what causes this error but all the examples I've seen don't seem to apply to this case. I am not iterating over either list, I am just running the loop based on the size of one of them. Most of what I've seen suggested to fix the ConcurrentModificationException
has been to create an Iterator and use remove()
but that only removes the next item in the iterator, and I need to remove a random item each time.
My question is, is there some obvious change I need to make to avoid the concurrency issue, or is this whole methodology fundamentally flawed?
P.S. There may be some inefficient code or some edge cases that haven't been handled yet. I am doing TDD and haven't gotten to all of the test cases yet. The current test this is breaking for is when filteredList
has a size of 0, and the subList
contains every group in the original groupList.
Once this test stops breaking I'll refactor and work on other test cases.
When you modify subList you are also modifying groupList. So if you are iterating over groupList during this process you would get ConcurrentModificationExceptions.
It doesn't sound like you need to modify groupList (since what you are after is the filteredList). So try making subList it's own list rather than a view over groupList:
List<Group> subList = new ArrayList<>(groupList.subList(firstMatch, lastMatch));