[java details] comparison of for loop, for each (enhanced for loop), forEach and Iterator iterators

Keywords: Java Back-end

[java details] comparison of for loop, for each (enhanced for loop), forEach and Iterator iterators

1, Background and conclusion

The background is that in the process of product development, there is an interface development that needs to intercept font json files. Because it involves multi-layer json content traversal, it can't get through the loop. This article mainly discusses the differences and relationships between for loops, for each (enhanced for loops), forEach and Iterator iterators in java. Conclusion first:
Contact:

  • 1. The function is the same. They are used to traverse the queue array or collection

difference:

  • Efficiency difference: for loop, for each loop is almost as efficient as Iterator, and forEach is slower.
  • Condition difference: the for loop needs to know the size of the array or collection to traverse, while for each, forEach and Iterator do not
  • Polymorphism difference: for loops, for each and forEach need to know the type of the set, even the type of elements in the set, that is, they need to access internal members, and polymorphism cannot be realized;
    Iterator is an interface type. It doesn't care about the type of set or array, and it can modify and delete the elements of the set at any time. For example:
Iterator iterator = integerList.iterator();
        while (iterator.hasNext()) {
            Integer integer = (Integer) iterator.next();
        }

When we need to traverse different sets, we only need to pass the iterator of the set, such as integerList.iterator(). This is the advantage of iterator. It does not contain any type information about the set it traverses, and can separate the operation of traversing the set from the underlying data structure of the set. Iterators unify access to collections. This is also one of the best practices for interface decoupling.

  • Differences in applicable scenarios:
    The for loop is generally used to handle complex loops, collections or arrays of predictable size. Because the index operation is involved, * * may cause index confusion due to developer problems, so it is not safe** A for loop is recommended for operations involving updating collection elements.
    For each can be used to traverse any set or array, and the operation is easy to understand, but it needs to understand the internal data type of the set, and it is not suitable for loops with array element update operations.
    forEach is basically similar to Iterator.
    Iterator is the most powerful. It can modify or delete the elements inside the collection at any time without knowing the types of elements and collections. When you need to implement the same traversal method for different containers, iterator is the best choice.

2, Content

The following is the efficiency test program and effect screenshot of for loop, for each, forEach and Iterator iterator I used:

public class ForIteratorForEachTest {

    public static void main(String[] args) {
        List<Integer> integerList = new ArrayList<Integer>();
        Integer intValue = 0;
        AtomicReference<Integer> value = new AtomicReference<>(0);
        long size = 100000;
        // Initialize the set to be tested
        for (int i = 0; i < size; i++) {
            integerList.add(i);
        }
        // start time
        long startTime = System.nanoTime();
        // for loop
        /*for (int i = 0; i < size; i++) {
            intValue = integerList.get(i);
        }*/
        // For each loop
       /* for (Integer integer : integerList) {
            intValue = integer;
        }*/
        // forEach loop
        /*integerList.forEach((integer) -> {
            value.set(integer);
        });*/
        // iterator
        Iterator iterator = integerList.iterator();
        while (iterator.hasNext()) {
            Integer integer = (Integer) iterator.next();
        }
        // End time
        long endTime = System.nanoTime();
        System.out.println("#========= Method time consuming: " + (endTime - startTime) + " nanosecond =========#");
    }

}



For loop and for each loop (enhanced for loop) are almost as efficient as Iterator. Even when the amount of data is small, for loop is more efficient. At 10w, 100w and 1000w, forEach is the slowest. By turning to the source code of JDK1.8, I found the reason:
1. Empty judgment is performed before traversing each element.
2. Because it is a stream pipeline operation, its element data structure needs to ensure atomicity. Here is another layer of performance consumption.

 /**
     * Performs the given action for each element of the {@code Iterable}
     * until all elements have been processed or the action throws an
     * exception.  Unless otherwise specified by the implementing class,
     * actions are performed in the order of iteration (if an iteration order
     * is specified).  Exceptions thrown by the action are relayed to the
     * caller.
     *
     * @implSpec
     * <p>The default implementation behaves as if:
     * <pre>{@code
     *     for (T t : this)
     *         action.accept(t);
     * }</pre>
     *
     * @param action The action to be performed for each element
     * @throws NullPointerException if the specified action is null
     * @since 1.8
     */
    default void forEach(Consumer<? super T> action) {
        // Empty first
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

3, Extend

In Effective Java, one of the God books of Java Chapter IX, section 58 He mentioned that the reason for preferring for each loops to traditional for loops is:
”Iterators and index variables are messy (you only need elements). In addition, they have the possibility of error. The iterator appears three times in each loop and the index variable appears four times, which gives a lot of opportunities to use the wrong variable. If you do this, there is no guarantee that the compiler will catch the problem. Finally, the two loops are very different. The for loop also needs to pay extra attention to the container type and add a little trouble to the type conversion. "For each loop (officially called" enhanced for statement ") solves all these problems. It eliminates confusion and error opportunities by hiding iterators or index variables. The paper also points out three scenarios where for each loop does not adapt:

  • Destructive filtration

If you need to traverse a set and delete the selected elements, you need to use an explicit iterator to call its remove method. You can usually avoid explicit traversal by using the removeIf method added by Collection in Java 8.

  • transformation

If you need to traverse a List or array and replace the values of some or all of its elements, you need a List iterator or array index to replace the values of the elements.

  • Parallel iteration

If you need to traverse multiple collections in parallel, you need to explicitly control iterators or index variables so that all iterators or index variables can be executed synchronously (as inadvertently demonstrated in the card and dice examples above). If you find yourself in any of these situations, use a normal for loop and be aware of the pitfalls mentioned in this entry.

reference material:
https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual

Posted by hanhao on Fri, 03 Dec 2021 14:16:39 -0800