javaarraylistdesign-patternsiteratorconcurrentmodificationexception

I have productListArray and I would like to add product into it but each product has unique ID and unique name and I am getting some errors


before I added the product to the non-empty list, I tried to validate if the product id and name of the product already existed in the list by going through the list and if there is no such id and name in the list then added the product to the list, but, I got this error #ConcurrentModificationException

-thanks for advance

import java.util.ArrayList;
import java.util.Iterator;

public class ProductList implements Iterator<Product> {

    private ArrayList<Product> productListArray = new ArrayList<>();

    /* Singleton Design begin */
    private static ProductList productListSingleton;

    private ProductList() {

    }// end of private constructor

    public static ProductList instance() {
        if (productListSingleton == null) {
            productListSingleton = new ProductList();
        }
        return productListSingleton;
    }

    /* Singleton Design Phase end */
    /*
     * method add product into list
     * 
     * @param Product Type
     */
    public void addProduct(Product product) {
// if the list is  empty just add the product into the list
        if (productListArray.isEmpty()) {
            productListArray.add(product);
        }
        /*
         * add product only if the id and name not existed in the productList
         */
        else {
            for (Product product1 : productListArray) {
                if (product1.getProductId() == product.getProductId()) {
                    System.out.println(" the product is already in the list");
                }
                else if (product1.getProductName().equals(product.getProductName())) {
                    System.out.println("choose another name for product");
                }
                else {
                    productListArray.add(product);
                }
            }
        }
    } // end of addProductMethod

    /*
     * remove the product from the ProductList Parameter product id
     */
    public void remove(int productId) {
        Iterator<Product> iteratorList = productListArray.iterator();
        while (iteratorList.hasNext()) {
            Product product = iteratorList.next();
            if (product.getProductId() == productId)
                iteratorList.remove();
        } // end of while
    } // end of remove method

    /* retrieve the productlist */
    public void retrieve() {
        Iterator<Product> iteratorList = productListArray.iterator();
        while (iteratorList.hasNext()) {
            System.out.println(iteratorList.next());
        }
    }

    @Override
    public boolean hasNext() {
        // TODO Auto-generated method stub
        if (next() == null) {
            return false;
        }
        else {
            return true;
        }
    }

    @Override
    public Product next() {
        // TODO Auto-generated method stub
        return next();
    }
}

Solution

  • From the code in your question:

    private ArrayList<Product> productListArray = new ArrayList<>();
    

    It is recommended to code to the interface and not to the implementation. Hence that line should be:

    private java.util.List<Product> productListArray = new ArrayList<>();
    

    You didn't post the code for class Product. In the below code, I added it as a record.

    I don't understand the need to make class ProductList a singleton but since it is, note the different ways to write a thread-safe singleton class.

    I also don't understand why class ProductList implements interface Iterator. The implementation is wrong and you don't use it anyway, so I just removed it in the below code.

    When you ask for help in finding out why your code is throwing an exception it is usually a good idea to post the stack trace of that exception.

    Your actual problem is that you are trying to modify productListArray while you are iterating over it. Note that the same problem exists in method remove.

    In the below code I also added a main method so that you can copy the code and run it.

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.ListIterator;
    
    public class ProductList {
    
        private List<Product> productListArray = new ArrayList<>();
    
        /* Singleton Design begin */
        private static ProductList productListSingleton = new ProductList();
    
        private ProductList() {
    
        }// end of private constructor
    
        public static ProductList instance() {
            return productListSingleton;
        }
    
        /* Singleton Design Phase end */
        /*
         * method add product into list
         * 
         * @param Product Type
         */
        public void addProduct(Product product) {
    // if the list is  empty just add the product into the list
            if (productListArray.isEmpty()) {
                productListArray.add(product);
            }
            /*
             * add product only if the id and name not existed in the productList
             */
            else {
                boolean canAdd = true;
                for (Product product1 : productListArray) {
                    if (product1.productId() == product.productId()) {
                        System.out.println(" the product is already in the list");
                        canAdd = false;
                        break;
                    }
                    if (product1.productName().equals(product.productName())) {
                        System.out.println("choose another name for product");
                        canAdd = false;
                        break;
                    }
                }
                if (canAdd) {
                    productListArray.add(product);
                }
            }
        } // end of addProductMethod
    
        /*
         * remove the product from the ProductList Parameter product id
         */
        public void remove(int productId) {
            ListIterator<Product> iteratorList = productListArray.listIterator();
            while (iteratorList.hasNext()) {
                Product product = iteratorList.next();
                if (product.productId() == productId)
                    iteratorList.remove();
            } // end of while
        } // end of remove method
    
        /* retrieve the productlist */
        public void retrieve() {
            Iterator<Product> iteratorList = productListArray.iterator();
            while (iteratorList.hasNext()) {
                System.out.println(iteratorList.next());
            }
        }
    
        public static void main(String[] args) {
            ProductList pl = ProductList.instance();
            pl.addProduct(new Product(1, "First"));
            pl.retrieve();
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
            pl.addProduct(new Product(1, "Second"));
            pl.retrieve();
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
            pl.addProduct(new Product(2, "First"));
            pl.retrieve();
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
            pl.addProduct(new Product(2, "Second"));
            pl.retrieve();
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
            pl.remove(1);
            pl.retrieve();
        }
    }
    

    Here is the output I get when I run the above code.

    Product[productId=1, productName=First]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     the product is already in the list
    Product[productId=1, productName=First]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    choose another name for product
    Product[productId=1, productName=First]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Product[productId=1, productName=First]
    Product[productId=2, productName=Second]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Product[productId=2, productName=Second]