Reputation: 255
I have this code in my adapter which displays a list of schools. There is also a search filter. Whenever the search filter has a value the list must show schools that contains the letters of search filter. Here is my code -
public boolean refreshAdapter() {
List<School> schools = cache().getSchools();
if (schoolList != null && !schoolList.isEmpty()) {
schoolList .clear();
}
schoolList = schools;
for (School school: schoolList) {
String name = school.getName();
String address = vehicle.getAddress();
if (name.contains(searchFilterText)|| address.contains(searchFilterText)) {
schoolList.add(school);
}
}
notifyDataSetChanged();
if (schoolList!= null) {
return schoolList.isEmpty();
}
return false;
}
How can I get this code running without concurrent modification exception? I tried using ListIterator but did not help me
Upvotes: 0
Views: 47
Reputation: 2981
Note that this Exception occurs because you must not add elements to the collection while iterating it. Did you get confused with schools
and shoolList
? Giving them more reasonable names can help a lot!
To do it correctly, you have to build a new filtered list (I commented the lines I changed)
// this is the new filtered list
schoolList = new ArrayList<>();
// iterate the original list
for (School school: schools) {
String name = school.getName();
String address = vehicle.getAddress();
if (name.contains(searchFilterText)|| address.contains(searchFilterText)) {
// add it to filtered list
schoolList.add(school);
}
}
Upvotes: 0
Reputation: 3949
The ConcurrentModificationException
originates because the schoolList
list is being modified within the process of iterating through that list. An alternative would be iterate the schools
list instead and make the additions to the schoolList
, which separates the list being iterated from the one being modified:
schoolList = new ArrayList<>();
for (School school: schools) {
String name = school.getName();
String address = vehicle.getAddress();
if (name.contains(searchFilterText)|| address.contains(searchFilterText)) {
schoolList.add(school);
}
}
Another alternative (using JDK 8 or above) is to filter the schools
list and capture the result into schoolList
:
schoolList = schools.stream()
.filter(school -> school.getName().contains(searchFilterText) || school.getAddress().contains(searchFilterText))
.collect(Collectors.toList());
Based on the current state of the code, it appears that you will be re-adding elements to the schoolList
, because it already contains those elements, hence why you are iterating over them. The code examples above result in lists that only contain the matching elements. If it desired to have the matching elements re-added to the schoolList
, as in the original question, you can replace the following line in the first example
schoolList = new ArrayList<>();
with
schoolList = new ArrayList<>(school);
This will create a copy of the school
list and store it in schoolList
before the iteration begins.
Be careful if this is the intended behavior, as it may cause an infinite loop. For example, in the original question, had a ConcurrentModificationException
not been thrown, if you add a School
object that matches the condition (name.contains(searchFilterText)|| address.contains(searchFilterText)
), it will also be iterated later on, which in turn would match the condition, and be re-added. This process would repeat infinitely. For example, suppose the only element in the schoolList
matches the condition, the following would be the results contained in schoolList
after each iteration:
Iteration 0:
matching school A <-- Current element of iteration
matching school A <-- [newly added element]
Iteration 1:
matching school A
matching school A <-- Current element of iteration
matching school A <-- [newly added element]
Iteration 2:
matching school A
matching school A
matching school A <-- Current element of iteration
matching school A <-- [newly added element]
And so on, infinitely.
Upvotes: 2
Reputation: 7166
You are getting ConcurrentModificationException
-s because you are iterating through a list while adding things to it. This is, in general, prohibited because adding stuff through iteration is confusing. In some cases, the programmers want the iteration to iterate through the recently added item, sometimes not. So java forces us to do either of these things explicitly.
You can fix it with a temporary list that stores the items you want to add to the list.
List<School> tempSchoolList = new ArrayList<>(); // this is the new list
// most of the things below comes from the original code
schoolList = schools;
for (School school: schoolList) {
String name = school.getName();
String address = vehicle.getAddress();
if (name.contains(searchFilterText)|| address.contains(searchFilterText)) {
tempSchoolList.add(school); // add the new list to the temp school list
}
}
schoolList.addAll(tempSchoolList);
Upvotes: 0