for and foreach forecah value references

1. Concept

for:

The for loop uses subscript indexing to determine the elements of an array or collection.

foreach:

1, foreach applies to arrays or implements i Collection class for terator. foreach uses the Iterator interface to traverse a collection.

2. When using a foreach loop to traverse a collection, you cannot use the methods that come with the collection to change the elements in the collection, such as adding and deleting elements. Otherwise, ConcurrentModificationException will be thrown. You can't modify the elements in the collection (no exceptions are reported), but you can modify the attributes of the elements.

3. foreach is value transfer, so the modification of the basic data type only works on formal parameters, not on actual parameters.

2. Example

1. Delete an element from a collection

(1) In the for loop, remove the elements of the list through the list.remove (index) method - normal operation

List<String> list = new LinkedList<String>();
list.add("Guangzhou");
list.add("Shengzhen");
list.add("Beijing");
//for list.remocve(index)--normal operation
for(int i=0;i<=list.size();i++){
    list.remove(0);
    i = 0;
}

(2) In the for loop, remove the elements of the list through the list.remove( value) method - normal operation

 //for list.remove(value)--normal operation
for(int i=0;i<3;i++){
    System.out.println(list);
    if(list.get(1)=="Shengzhen")
    list.remove("Shengzhen");
}

(3) In the foreach loop, remove the elements of the list through the list.remove (index) method -- ConcurrentModificationException

The time when the error is reported is when the foreach loop traverses for the second time.

The place where the error is reported is the point of for (String s:list) .

The reason is that the underlying foreach is an iterator.

If the collection is traversed with an iterator, call the collection's own list.remove(value), or list.remove(index) to delete the elements of the collection list itself. During the first traversal, calling the remove method will successfully remove the elements.

In the second traversal, the iterator will call the iterator.hasNext() method, and hasNext() is to determine whether there is a next element. If the collection has more than two elements, iterator.hasNext() will return true, indicating that there are more elements in the collection next. Then the iterator.next() method will be called to get the next element of the collection. At this time, some judgment operations will be performed inside the iterator.next() (the length will be longer and will be described in detail next time), and then iterator.next() will return ConcurrentModificationException.

        //foreach list.remove(value)--ConcurrentModificationException
        for (String s:list) {
            list.remove(s);
        }
        System.out.println(list);

When the number of list sets is only two, no error will be reported.

When there are only two elements, after deleting the first element, there is only one left. At this time, the hasNext() of the iterator is called as false, so the traversal will not continue. Nor will it continue to call the iterator's next() . Because the first element in the list is deleted, the index of the second element is changed from 1 to 0, so the iterator thinks that the second element has been traversed and acquired, and will not pass next() to it. Get it, thus showing it. In fact, the second element is not traversed, but because the first element is deleted, it becomes the first element of the modified array.

If the set list has three elements, hasNext() will not return false, it will return true, and then use next() to get the second element of the list (that is, the third element before the set is not deleted), at this time due to The internal judgment mechanism of next() (will be explained in detail next time), in the case of calling the remove method of the list itself to delete an element, a ConcurrentModificationException exception will occur.

        List<String> list = new LinkedList<String>();
        list.add("Guangzhou");
        list.add("Shengzhen");    

        for (String s:list) {
            System.out.println("foreach in the loop list before deletion:"+list);
            list.remove(s);
            System.out.println("foreach in the loop list after deletion:"+list);
        }
        System.out.println(list);    
foreach in the loop list before deletion:[Guangzhou, Shengzhen]
foreach in the loop list after deletion:[Shengzhen]
[Shengzhen]

(4) In the foreach loop, remove the elements of the list through the list.remove( value) method -- ConcurrentModificationException

The reason is the same as above 👆 to remove list collection elements through the list.remove( index) method.

So the same happens when the set has only two elements.

        //foreach list.remove(index)--ConcurrentModificationException
        int i=0;
        for (String s:list) {
            list.remove(i);
        }    

2. Modify the elements in the collection

The for loop is to obtain the elements of the collection according to the index of the collection, so as to modify the collection.

foreach is pass-by-value, so if the actual parameter is a primitive data type, modifications to the formal parameter will not affect the actual parameter. If the actual parameter is an object reference, modifications to the formal parameter affect the actual parameter.

(1) Use foreach to modify basic data types

 

        int[] arr = new int[10];
        System.out.println("foreach increased in i");
        for(int i:arr){
            i++;
            System.out.println(i);
        }
        System.out.println("arr in the array i");
        for(int i:arr){
            System.out.println(i);
        }    

 

The output results are as follows. It can be seen that when the actual parameter of foreach is a basic data type, the value assigned to the formal parameter is a copy of the actual parameter. Modifications to formal parameters will not affect actual parameters.

foreach increased in i
1
1
1
1
1
1
1
1
1
1
arr in the array i
0
0
0
0
0
0
0
0
0
0

(2) Modify the object with foreach

class Per{
    Per(){
    }

    Per(String name,int age){
        this.name = name;
        this.age = age;
    }

    private String name;

    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}
public class TestForeach {
    public static void main(String[] args) {
        Per p1 = new Per("oneone",11);
        Per p2 = new Per("twotwo",12);
        Per p3 = new Per("threethree",13);

        List<Per> list = new LinkedList<Per>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        for (Per p:list) {
            p.setName("fourfour");
        }
        list.forEach(per -> {
            System.out.println(per.getName());
        });
    }
}

The output results are as follows. It can be seen that when the actual parameter of foreach is a reference type, in the case of value reference, what is assigned to the formal parameter is a copy of the actual parameter reference address value. Modifications to the object pointed to by the reference address value of the formal parameter will affect the object pointed to by the address value of the actual parameter reference, because the address values ​​of the two references are the same and point to the same object.

fourfour
fourfour
fourfour

 

Reference articles:

https://blog.csdn.net/li_xunhuan/article/details/99075208

https://blog.csdn.net/qq_26545305/article/details/78485224

Posted by insight on Sat, 07 May 2022 04:59:02 +0300