Iterator迭代器解決[爲何禁止在foreach內增刪]?

原文鏈接:Iterator迭代器解決[爲何禁止在foreach內增刪]?
2020-01-13 12:08:06:332 星期一 🌙


迭代器的應用場景:

1、對集合進行增加刪除,禁止使用foreach,循環的動態操作
2、倒序遍歷
3、遍歷循環

步入正題:爲何禁止在foreach內進行增刪?

先看一下代碼:

        /**
         *         正例:
         *         Iterator<String> iterator = list.iterator();
         *         while (iterator.hasNext()) {
         *             String item = iterator.next();
         *             if (刪除元素的條件) {
         *                 iterator.remove();
         *             }
         *         }
         *         反例:
         *         List<String> list = new ArrayList<String>();
         *         list.add("1");
         *         list.add("2");
         *         for (String item : list) {
         *             if ("1".equals(item)) {
         *                 list.remove(item);
         *             }
         *         }
         */

這段代碼是,在阿里的開發手冊中的一段代碼。

我們先看下面場景:


        /**
         * 場景一:對集合進行刪除,增加、for循環
         * 錯誤:這裏會報出數據越界異常,
         * 因爲:remove掉一個元素後,整個長度發生變化,所以發生異常
         * 改進:採用forList.size()動態
         */
        List<String> forList = new ArrayList<>();
        forList.add("a");
        forList.add("b");
        forList.add("c");
        int length = forList.size();
        for (int i = 0; i < length; i++) {
            if ("a".equals(forList.get(i))) {
                forList.remove(i);
            }
        }
        System.out.println(forList);
        /**
         * 產生新問題:
         * 錯誤:運行便會發現:將b移除不完整,
         * 因爲:刪除後整個遊標向下,數組向上,剛好空出1個位置,
         * 緊接着的第二位沒有進行比對,所以產生問題
         * 解決:數據長度減一與遊標保持統一
         */
        List<String> forList1 = new ArrayList<>();
        forList1.add("a");
        forList1.add("b");
        forList1.add("b");
        forList1.add("c");
        for (int i = 0; i < forList1.size(); i++) {
            if ("b".equals(forList1.get(i))) {
                forList1.remove(i);
                i--;
            }
        }
        System.out.println(forList1);

通過上個場景,知道在for循環內,爲啥不建議用remove/add

在foreach循環內,再接着看下面這個場景?


        /**
         * 場景二:
         * foreach循環,的remove/add操作
         */
        List<String> forEach = new ArrayList<>();
        forEach.add("a");
        forEach.add("b");
        forEach.add("c");
        for (String each : forEach) {
            if ("a".equals(each)) {
                forEach.remove(each);
            }
        }
        /**
         * 產生的異常:
         *   Exception in thread "main" java.util.ConcurrentModificationException
         * 	    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
         * 	    at java.util.ArrayList$Itr.next(ArrayList.java:859)
         */
        /**
         * 源碼:Itr實現了Iterator接口(刪減部分)
         *  private class Itr implements Iterator<E> {
         *         @Override
         *         @SuppressWarnings("unchecked")
         *         public void forEachRemaining(Consumer<? super E> consumer) {
         *             Objects.requireNonNull(consumer);
         *             final int size = ArrayList.this.size;
         *             int i = cursor;
         *             if (i >= size) {
         *                 return;
         *             }
         *             final Object[] elementData = ArrayList.this.elementData;
         *             if (i >= elementData.length) {
         *                 throw new ConcurrentModificationException();
         *             }
         *             while (i != size && modCount == expectedModCount) {
         *                 consumer.accept((E) elementData[i++]);
         *             }
         *             // update once at end of iteration to reduce heap write traffic
         *             cursor = i;
         *             lastRet = i - 1;
         *             checkForComodification();
         *         }
         *
         *          如果有更改則拋出ConcurrentModificationException異常,
         *
         *         final void checkForComodification() {
         *         之前的版本不等於,當前的版本,判斷爲數據更新了。
         *         那麼?爲什麼產生這樣的判斷呢,因爲你刪除後變爲新數組,來不及
         * 更新版本,jvm不知道你當前數據狀態,是否變化,無法再進行遍歷
         *             if (modCount != expectedModCount)
         *                 throw new ConcurrentModificationException();
         *         }
         *     }
         */
        /**
         * 改進:
         *
         */
        List<String> forEachIterator = new ArrayList<>();
        forEachIterator.add("a");
        forEachIterator.add("b");
        forEachIterator.add("c");
        java.util.Iterator<String> iterator = forEachIterator.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if ("a".equals(next)) {
                iterator.remove();
            }
        }

這裏:foreach實現的就是迭代器。

補充:倒序循環

   /**
         * 場景三:
         * 應用:倒序遍歷
         */
        List<String> forEachIteratorDown = new ArrayList<>();
        forEachIteratorDown.add("a");
        forEachIteratorDown.add("b");
        forEachIteratorDown.add("c");
        ListIterator<String> item = forEachIteratorDown.listIterator();
        //這裏需要先將指針移向最後一位,再進行倒敘
        while (item.hasNext()) {
            item.next();
        }
        while (item.hasPrevious()) {
            String previous = item.previous();
            System.out.println(previous);
        }

源碼:待挖掘,再做記錄備註。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章