java How to Delete an Object I Specify in list

  • 2021-12-12 04:34:00
  • OfStack

Directory traversal list, 3 ways to delete specified objects 1, then define an List to save objects to be deleted 2, not using for-each loop, using reverse loop to delete 3, using iterator to delete Iterator working mechanism List set the correct gesture of deleting elements commonly used error ways are as follows

Traversing list, 3 Ways to Delete Specified Objects

1. Define another List to save the objects to be deleted

Modify part of the code:


 List<User> userRemove = new ArrayList<User>();
        // Find out which users to delete 
        System.err.println(" Users to delete :");
        for (User result : list)
        {
            if (result.getId() == 1 || result.getId() == 3)
            {
                userRemove.add(result);
                System.err.println("id:" + result.getId() + "\tname:" + result.getName());
            }
        }
        list.removeAll(userRemove);
        // Remaining users 
        System.err.println(" Remaining users :");
        for (User result : list)
        {
            System.err.println("id:" + result.getId() + "\tname:" + result.getName());
        }

2. Instead of for-each loop, use reverse loop to delete


for(int i=list.size()-1;i>=0;i--)
                {
                    User result = list.get(i);
                    if (result.getId() == 3)
                    {
                        list.remove(result);
                        System.err.println("id: " + result.getId() + "\tname: " + result.getName());
                    }
                }

3. Delete with an iterator


Iterator<User> it = list.iterator();
        while (it.hasNext())
        {
            User userObj = it.next();
            if (userObj.getId() == 3)
            {
                it.remove();
            }
        }
        // Remaining users 
        System.err.println(" Remaining users :");
        for (User result : list)
        {
            System.err.println("id:" + result.getId() + "\tname:" + result.getName());
        }

PS: Traversing with for-each actually uses Iterator iterator

Working Mechanism of Iterator

Iterator works in a separate thread and has an mutex lock, which means that Iterator does not allow the iterated object to be changed when it works.

When Iterator was created, a memory index table (single linked list) was established, which pointed to the original object. When the number of original objects changed, the contents of this index table did not change synchronously, so when the index pointer moved down, the object to be iterated could not be found, resulting in an error.

List, Set, etc. are dynamic data structures with variable number of objects, but Iterator is a one-way immutable data structure, which can only be read in sequence and cannot be operated in reverse order. When the original data pointed by Iterator changes, Iterator loses its way.

Three ways to facilitate future study!

The List collection removes the correct gesture of an element

When reading Alibaba Statute, I found that there is a statute about List, "Do not operate remove/add of elements in foreach, please use Iterator mode for remove". Then I remembered that when I was doing my own project, I deleted the logical subscript of a certain 1 element. At that time, I remembered that the processing was stored with a new List, and then removed all the elements that met the rules from the original List as a whole. Now I will make a summary of 1. With this Iterator, we can mainly avoid the subscript overstepping or traversing the next 1 data that meets the rules.

Pull out the gesture of correctly deleting elements first. The correct posture is to use remove method of Iterator. The specific operation is as follows:


public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        Iterator<Integer> iterator = lists.iterator();
        while (iterator.hasNext()){
            Integer obj = iterator.next();
            if(3==obj || 4==obj){
                iterator.remove();
            }
        }
        System.out.println(lists);
    }

Attach your own stupid operation mode:


public static void main(String[] args){
            List<Integer> lists = new ArrayList<Integer>();
            List<Integer> listscopy = new ArrayList<>();
            lists.add(1);
            lists.add(2);
            lists.add(3);
            lists.add(4);
            lists.add(5);
            int size = lists.size();
            for (int i = 0; i < lists.size(); i++) {
                if(3==lists.get(i) || 4 == lists.get(i)){
                    listscopy.add(lists.get(i));
                }
            }
            lists.removeAll(listscopy);
            System.out.println(lists);
        }

There are three common ways to make mistakes

In the first way, subscript overstepping often occurs. The main reason for this is that we set our length to a fixed value during the loop. It is ignored that the length of list is reduced when the conditions are met.


public static void main(String[] args) {
 List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        int size = lists.size();  //  Fixed length setting will cause the element subscript to cross the boundary. If the for The medium variable is directly replaced by lists.size() Is that all right? 
        for (int i = 0; i < size; i++) {
            if(3==lists.get(i) || 4 == lists.get(i)){
                lists.remove(i); //lists.remove(lists.get(i));
            }
        }
        System.out.println(lists);
 }

The second way, which is mentioned in the above note, Since subscript overruns will occur, I can't use dynamic size, but using this method will produce another situation, that is, one element after remove element will be ignored. This is because after deleting the element that conforms to the rule, the length of list will be reduced by 1, while the following element will be supplemented by one bit, resulting in two elements corresponding to the current i value.


public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        int size = lists.size();
        for (int i = 0; i < lists.size(); i++) {
            if(3==lists.get(i) || 4 == lists.get(i)){
                lists.remove(i); //lists.remove(lists.get(i));
            }
        }
        System.out.println(lists); //  Print [1, 2, 4, 5]  At this time, the 4 Ignore 
    }

The third mode is caused by using the enhanced FOR loop. This method will directly report errors:


ERRORInfo:
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
       for (Integer i : lists){
           if(3==i || 4==i){
               lists.remove(i);
           }
       }
        System.out.println(lists);
    }

In this case. Mainly set traversal is using Iterator, Iterator is working in a separate thread, and has a mutex. After Iterator is created, a single-linked index table pointing to the original object will be established. When the number of original objects changes, the contents of this index table will not change synchronously, so when the index pointer moves backward, the object to be iterated cannot be found. Therefore, according to fail-fast principle, Iterator will immediately throw java. util. ConcurrentModificationException exception. Therefore, Iterator does not allow the iterated objects to be changed when it works.


Related articles: