passing an copy of arraylist to avoid concurrent modification exception - java

I have below java piece of code that throws ConcurrentModificationException below is the java piece of code
below is the lists that are being declared
List<BrokerInvoiceLineItem> brokerInvoiceLineItems= new ArrayList<BrokerInvoiceLineItem>();
brokerInvoiceLineItems=brokerInvoice.getLineItems();
below is the the piece of code that is throwing concurrentmodification exception
if (brokerInvoiceLineItems == null) {
brokerInvoiceLineItems = brokerInvoiceHome.findLineitemsByInvoiceId(brokerInvoice.getId());
}
for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {
if (fetchNewAndOldCFandAmend(brokerInvoiceLineItem)) {
if (!isAnyValid)
isAnyValid = true;
}
}
now the issue is that if brokerInvoiceLineItems is not null then for the first iteration it goes inside the loop and the value is set true of variable named isAnyValid but as soon the first iteration is over then for the second iteration it goesagain to the line for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems){ and then it does not go the next line it throws concurrent modification exeption
so this means it must be modifying brokerInvoiceLineItems size while iterating through it. This is probably occurring in fetchNewAndOldCFandAmend so i am consider making a copy of brokerInvoiceLineItems and modifying the copy instead. so please advise how can i pass the copy to fetchNewAndOldCFandAmend(brokerInvoiceLineItem)
Also please advise how to use copyonwriteArray list also to avoid such error

I think you get this exception when you remove some items of brokerInvoiceLineItems.
To avoid this exception, use an iterator
Iterator<BrokerInvoiceLineItem> iterator = brokerInvoiceLineItems.iterator();
while(iterator.hasNext()) {
BrokerInvoiceLineItem brokerInvoiceLineItem = iterator.next();
// your code
}
instead of
for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {
so your code is:
Iterator<BrokerInvoiceLineItem> iterator = brokerInvoiceLineItems.iterator();
while(iterator.hasNext()) {
BrokerInvoiceLineItem brokerInvoiceLineItem = iterator.next();
if (fetchNewAndOldCFandAmend(brokerInvoiceLineItem)) {
if (!isAnyValid)
isAnyValid = true;
}
}

I'm assumming that you are modifying the brokerInvoiceLineItems in the method fetchNewAndOldCFandAmend. You can use a CopyOnWriteArrayList
instead of the ArrayList. This allows you to iterate the list and at the same time update it. There is some cost to this since it creates a new array everytime you add something to it. A sample code would look like this:
// Member field declaration
List<BrokerInvoiceLineItem> brokerInvoiceLineItems;
// Retrieve the list of objects
List<BrokerInvoiceLineItem> items = brokerInvoice.getLineItems();
if (items == null) {
items = brokerInvoiceHome.findLineitemsByInvoiceId(brokerInvoice.getId());
}
// Initialize your member variable to be a
// CopyOnWriteArrayList with the above elements
brokerInvoiceLineItems = new CopyOnWriteArrayList<>(items);
// Iterate over the elements and possibly update the list from
// the fetchNewAndOldCFandAmend method
for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {
if (fetchNewAndOldCFandAmend(brokerInvoiceLineItem)) {
if (!isAnyValid)
isAnyValid = true;
}
}
My code assumes that you have a class which stores a list of BrokerInvoiceLineItem and it's initialization is made in the constructor.
Usually it's a bad idea to iterate over a list and call another method which updates it. You can use an iterator to traverse it and remove certain elements. Your fetchNewAndOldCFandAmend maybe can be used to indicate if the current item should be removed from the list and call the iterator's remove method.

You should create a new ArrayList and add to it all the elements of your previous ArrayList object.
ArrayList<BrokerInvoiceLineItem> otherList = new ArrayList<BrokerInvoiceLineItem>();
otherList.addAll(brokerInvoiceLineItems);
Note: if you change your for statement for another like:
for(int i=0;i<brokerInvoiceLineItems.size();i++){
You'll not get that ConcurrentModificationException.
Update: example code:
if (brokerInvoiceLineItems == null) {
brokerInvoiceLineItems = brokerInvoiceHome.findLineitemsByInvoiceId(brokerInvoice.getId());
}
ArrayList<BrokerInvoiceLineItem> otherList = new ArrayList<BrokerInvoiceLineItem>();
otherList.addAll(brokerInvoiceLineItems);
for (BrokerInvoiceLineItem brokerInvoiceLineItem : brokerInvoiceLineItems) {
if (fetchNewAndOldCFandAmend(otherList)) {
if (!isAnyValid)
isAnyValid = true;
}
}

Related

Deleting specific object from ArrayList using for-loop

I am trying to delete one object from an ArrayList, but after iterating through the list with the for loop i'm stuck at what to do next. nameInput is a lowercase string from the user.
If i run this it prints the object from arr list equal to the input from nameInput. But I cannot understand how to go from printing that object to deleting it?
I'm sure this is a stupid question but the 50+ answers i have read and tried all seem to fail me (or more likely I fail to understand them). I have tried the list.remove and removeIf.
private ArrayList<Arr> arr = new ArrayList<>();
private void removeItem() {
for (Object arr : arr) {
if (((Arr) arr).getName().equals(nameInput())) {
System.out.println(arr);
break;
} else {
System.out.println("Error");
}
}
}
Using for loop
List<Arr> arr = new ArrayList<>();
for (Arr item : arr) {
if (item.getName().equals(nameInput())) {
arr.remove(item);
break;
}
}
If not call break after remove element, you get ConcurrentElementException
Note from #Aomine: you have to implement correct Arr.equals() method.
Using Iterator
List<Arr> arr = new ArrayList<>();
Iterator<Arr> it = arr.iterator();
while (it.hasNext()) {
Arr items = it.next();
if (item.getName().equals(nameInput())) {
it.remove();
break; // you can continue iterating and remove another item
}
}
Using Streams
List<Arr> arr = new ArrayList<>();
arr.removeIf(item -> item.getName().equals(nameInput()));
Remove all items that match given condition
This is not good to remove element from ArrayList. In case you know that you have to remove element from the middle of the List, do use LinkedList.
You are trying to remove an item while you are traversing/iterating the list in the for loop. You cannot remove an item from the list iterating it in a for loop. Use an Iterator instead and invoke arr.remove().
If you use Java 8 you could do
private void removeItem() {
arr.removeIf(t -> t.getName().equals(nameInput));
}
Note that this will remove all objects with name equal to nameInput
Also you should change your declaration of arr to
List<Arr> arr = new ArrayList<>();
A couple of things here...
The loop variable receiver type should ideally be Arr instead of Object as the list contains Arr objects. This also means you no longer need the cast you're performing.
You could remove the item via remove(Object o) but this requires overriding equals and hashcode based on name only. Another option is via an iterator but this would mean changing your code completely. Thus, to keep it as close to your code as possible you can use a for loop; get the index which the object is located and then remove.
Thus, you can do:
for(int i = 0; i < arr.size(); i++){
if (arr.get(i).getName().equals(nameInput)) {
Arr obj = arr.remove(i); // remove the item by index
System.out.println(obj); // print the object
break; // terminate the loop iteration
}
}

Arraylist iterator concurrent modification exception when removing item

So this question is a little bit different from the others i've found on here about concurrent exception when modifying the list- because this happens when im modifying an internal list of an object within the list. This is the only method accessing the internal list
Here's where i call the method
public void interactWithItem(int targetIDX, int targetIDY){
for(Iterator<Item> it = listOfAllItems.iterator(); it.hasNext();){
Item tempItem = it.next();
//Maybe i should refine more, in world, so forth
if(tempItem.tilePosX == targetIDX && tempItem.tilePosY == targetIDY){
if(tempItem.name.equals("chest")){
System.out.println("Interacting with Chest!");
if(!tempItem.containedItems.isEmpty()){
for(Iterator<Item> tempIt = tempItem.containedItems.iterator(); tempIt.hasNext();){
Item tItem = tempIt.next();
System.out.println("Chest contains "+tItem.name+" "+tItem.amount);
Character.c.addItem("player", tItem.name, tItem.amount);
removeContainedItem("chest", tItem.name);
}
}else{
System.out.println("Chest is empty");
}
}
}
}
}
Here's the method that causes the issue, if i comment out the i.remove(); the issue seizes to happen- so its only upon removal, yet no other method or class is accessing the internal list ?
public void removeContainedItem(String containerName, String itemName){
System.out.println("Removing "+itemName+" in "+containerName);
for(Iterator<Item> it = listOfAllItems.iterator(); it.hasNext();){
Item tItem = it.next();
if(tItem.name.equals(containerName)){
for(Iterator<Item> i = tItem.containedItems.iterator(); i.hasNext();){
Item tempItem = i.next();
System.out.println(tempItem.name);
if(tempItem.name.equals(itemName)){
i.remove();
}
}
}
}
}
Thanks for all the help! Hope someone can clarify and give me instructions as to how i might go about fixing this thing? Im a bit at a loss.
Concurrent Modification Exception occurs when a collection is modified between the iterations. We can use ConcurrentHashMap or CopyOnWriteArrayList to overcome this issue.
If hitting UnsupportedOperationException, change the ArrayList to LinkedList
Might be :
**Item tItem = tempIt.next();**
When you create an item you then add it to more than one list. And when one of them tries to modify it you can get exceptions. Because bouth lists are using the same item, exactly the same one.
Fix that might help would be :
Item newItem = new Item();
newItem = tempIt.next();
Simply create new item for each list and modify them as you please.
Or create a new list for :
public void removeContainedItem(String containerName, String itemName){
And modify new copy list with items, then set previous list to modified one.

Iteration is quit after first iteration

I am trying to compare two different List and remove the duplicates. However, the two lists have two different object types and only common attribute is app name.
Here is the code,
public List<TvAppsType> getAvailableAppsTypesByCompanyIdSecond(int comapnyId) {
// put apps to the model that belong to the given company id
TVAppService tvAppService = new TVAppService();
List<ThreatviewApp> apps = new CopyOnWriteArrayList<ThreatviewApp>();
apps = tvAppService.getAllAppsforCompanyId(comapnyId);
// get list of app types
TvAppTypeService types = new TvAppTypeService();
List<TvAppsType> apptypes = new CopyOnWriteArrayList<TvAppsType>();
apptypes = types.getAppTypes();
// add the items to collection for removing
for(TvAppsType app : apptypes){
System.out.println("-----------------------");
System.out.println("app : " + app.getAppType_name());
}
Iterator<TvAppsType> itertypes = apptypes.iterator();
Iterator<ThreatviewApp> it = apps.iterator();
while (itertypes.hasNext()) {
TvAppsType apptype = itertypes.next();
while (it.hasNext()) {
ThreatviewApp tvapp = it.next();
if (tvapp.getApp_name().trim().equals(apptype.getAppType_name().trim())) {
itertypes.remove();
}
}
}
for(TvAppsType app : apptypes){
System.out.println("-----------------------");
System.out.println("app : " + app.getAppType_name());
}
return apptypes;
}
Problem is this works only in first iteration, I suspect that after the List is modified, the iteration behavior is unspecified.
void remove() Removes from the underlying collection the last element
returned by this iterator (optional operation). This method can be
called only once per call to next(). The behavior of an iterator is
unspecified if the underlying collection is modified while the
iteration is in progress in any way other than by calling this method.
As I am trying to modify the lists runtime, I used CopyOnWriteArrayList
bascically, I followed this article article
why the iteration stop after first one? How to fix this and remove all duplicates?
In addition to #Eran's answer, you have another problem. Once you have removed a TvAppsType (in the inner while loop), you should never attempt to remove the same object again. Also, quitting the inner loop as soon as possible will speed up your algorithm.
So, the inner loop should look like this:
while (it.hasNext()) {
ThreatviewApp tvapp = it.next();
if (tvapp.getApp_name().trim().equals(apptype.getAppType_name().trim())) {
itertypes.remove();
break;
}
}
You have to reset the iterator of the inner loop if you wish to iterate more than once on the apps list. Otherwise, the inner while loop will iterate over the apps list only one time, after which it.hasNext() will be false.
Iterator<TvAppsType> itertypes = apptypes.iterator();
while (itertypes.hasNext()) {
TvAppsType apptype = itertypes.next();
Iterator<ThreatviewApp> it = apps.iterator(); // the inner iterator must be
// initialized in each iteration
// of the outer loop
while (it.hasNext()) {
...

java while (LinkedList.iterator().hasNext()) does not work

I have the following while loop, if I put this.boatTripsList.iterator().hasNext() in the while loop condition, it throws error. When I create iterator then put in the while loop condition, it will work then. Why is this? Thanks & Regards. (the second version throws error)
public Journey(List<BoatTrip> trips) {
this.boatTripsList = new LinkedList<BoatTrip>();
Iterator<BoatTrip> iterator = trips.iterator();
//add the given boat trips to the boattrips list
while (iterator.hasNext()) {
BoatTrip thistrip = iterator.next();
this.boatTripsList.add(thistrip);
}
}
public Journey(List<BoatTrip> trips) {
this.boatTripsList = new LinkedList<BoatTrip>();
//add the given boat trips to the boattrips list
while (trips.iterator().hasNext()) {
BoatTrip thistrip = iterator.next();
this.boatTripsList.add(thistrip);
}
}
This is normal: if your while condition is while(trips.iterator().hasNext()), you create a new iterator each time. If your list is not empty, the condition will therefore always be true...
While in the loop itself, you use the iterator you created before entering the loop... As a result, you'll get a NoSuchElementException when this iterator is empty.
Use:
final Iterator<Whatever> = list.iterator();
Whatever whatever;
while (iterator.hasNext()) {
whatever = iterator.next();
// do whatever stuff
}
But for walking lists, a foreach loop is preferred:
for (final BoatTrip trip: tripList)
// do whatever is needed
And if you want to add the contents of a list to another, use .addAll():
// no need for the "this" qualifier, there is no name conflict
boatTripList.addAll(trips);
You aren't using the iterator you requested on the first line of your code there - you're requesting a new one each time, so it will always have a next.
A call to .iterator() obtains a new iterator. If you do that in the loop, you will always obtain a new iterator rather than iterating over an existing iterator.
this.boatTripsList.iterator().hasNext() is wrong
this.boatTripsList.hasNext() is correct

Java Concurrent Modification Exception Error

Im playing around with some code for my college course and changed a method from
public boolean removeStudent(String studentName)
{
int index = 0;
for (Student student : students)
{
if (studentName.equalsIgnoreCasee(student.getName()))
{
students.remove(index);
return true;
}
index++;
}
return false;
}
To:
public void removeStudent(String studentName) throws StudentNotFoundException
{
int index = 0;
for (Student student : students)
{
if (studentName.equalsIgnoreCase(student.getName()))
{
students.remove(index);
}
index++;
}
throw new StudentNotFoundException( "No such student " + studentName);
}
But the new method keeps giving a Concurrent Modification error. How can I get round this and why is it happening?
It is because you continue traversing the list after performing remove().
You're reading and writing to the list at the same time, which breaks the contract of the iterator underlying the foreach loop.
Use Iterator.remove()
for(Iterator<Student> iter = students.iterator(); iter.hasNext(); ) {
Student student = iter.next();
if(studentName.equalsIgnoreCase(student.getName()) {
iter.remove();
}
}
It is described as the following:
Returns the next element in the iteration.
Throws NoSuchElementException if the iteration has no more elements.
You can use Iterator.hasNext() to check if there is a next element available.
foreach construct uses an underlying Iterator.
In the second method you continue to iterate even after removing an item from the list. This is resulting in the exception that you see. Take a look at this statement taken from ConcurrentModificationException documentation:
For example, it is not generally permissible for one thread to modify
a Collection while another thread is iterating over it. In general,
the results of the iteration are undefined under these circumstances.
Some Iterator implementations (including those of all the general
purpose collection implementations provided by the JRE) may choose to
throw this exception if this behavior is detected.
You are not allowed to remove an element from your collection while you iterate over it. The iterator detects a structural change during its usage, and throws the exception. Many collections are implemented in such a way.
Use the iterator directly instead:
Iterator<Student> it = students.iterator();
while (it.hasNext()) {
Student student = it.next();
if (studentName.equalsIgnoreCase(student.getName())) {
it.remove();
return true;
}
}
return false;
you can avoid concurrent modification error buy just breaking the loop after removing the element or if the method has a return type return a value after removing the element.
This error occurs because you are trying to alter the size of a collection while you are iterating it. If you have 10 students, you start your loop expecting to go through 10 iterations. When you remove a student, how many iterations do still need to go? The answer obviously depends on where you removed your student from the list and where you currently are in your iteation. Obviously, java cannot know this.
To get around this, you must use an iterator. You can accomplish this as follows:
Iterator<Student> studentsIterator;
for(studentsIterator = students.iterator(); studentsIterator.hasNext();)
{
Student student = studentsIterator.next();
if(student... /* condition */)
{
studentIterator.remove(); //This removes student from the collection safely
}
}
You are not allowed to remove an element from students collection while iterating through it.
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances.
http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html
Try changing to
Iterator<Student> itr = students.iterator();
while (itr.hasNext()) {
Student student = itr.next();
if (studentName.equalsIgnoreCase(student.getName()))
{
itr.remove();
}
}
If you want to remove inside a loop you should use an iterator and its remove method
public boolean removeStudent(String studentName)
{
Iterator<Student> itS = students.iterator();
while(itS.hasNext())
{
Student student = itS.next();
if (studentName.equalsIgnoreCasee(student.getName()))
{
itS.remove();
return true;
}
}
return false;
}
You shouldn't delete objects from a collection while using
a for-each statement - this will cause exceptions as your iterator faces a changed collection in the course of its iterations. (the for loop)
either use a regular for loop (for int i = 0; i < 100; i++) etc...
or keep the objects to remove in a list, and remove them outside of the for loop.
Also, you remove the object by index where index is : 0 , 1 , 2
but index should actaully be the index of the student.

Categories