Java中的遍歷(遍歷集合或數組的幾種方式)

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文主要總結了"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中遍歷集合或數組的幾種方式,並介紹了各種遍歷方式的實現原理,以及一些最佳實踐。最後介紹了"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"集合類迭代器的快速失敗("},{"type":"codeinline","content":[{"type":"text","text":"fail-fast"}]},{"type":"text","text":")機制。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"Java中的循環結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"遍歷必然需要使用到循環結構,"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中有以下幾種循環結構:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"while"}]},{"type":"text","text":"語句"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"do...while"}]},{"type":"text","text":"語句"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"基本"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"語句"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"語句"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於"},{"type":"codeinline","content":[{"type":"text","text":"do...while"}]},{"type":"text","text":"語句,其第一個循環體是必須會執行的,這對於空集合或者空數組是不適用的。所以我們一般不會使用"},{"type":"codeinline","content":[{"type":"text","text":"do...while"}]},{"type":"text","text":"語句來進行遍歷。其餘三種都是我們經常用來遍歷的語法結構。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"語句和"},{"type":"codeinline","content":[{"type":"text","text":"while"}]},{"type":"text","text":"語句在一般情況下可以互相轉化,下文我們並不將兩種語句單獨區分,會根據場景選擇使用更加簡單的方式。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"遍歷數組"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1. 使用下標遍歷"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用循環遍歷數組下標範圍,在循環體中用下標訪問數組元素:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"for (int i = 0; i < array.length; i++) {\n System.out.println(array[i]);\n}"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2. 增強for循環"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環語法結構來對數組進行遍歷:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"for (int value : array) {\n System.out.println(value);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環 其實只是一種語法糖,使用 增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環 在遍歷數組時,在編譯過程會將其轉化爲 \"使用下標遍歷\" 的方式,在字節碼層面其實等價於第一種方式,效率上也沒有太大差別。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環語法更詳細的介紹,請移步:"},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2","title":""},"content":[{"type":"text","text":"Java Language Specification - 14.14.2. The enhanced for statement"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"JAVA中的迭代器"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 面向對象編程裏,迭代器模式是一種設計模式,是一種最簡單也最常見的設計模式。迭代器模式提供了一種方法順序訪問一個集合對象中的各個元素,而又不暴露其內部的表示。"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中也提供了對迭代器模式的支持,主要是針對"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"的各種集合類進行遍歷。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"接口是"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中對迭代器的抽象接口定義,其定義如下:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface Iterator {\n // 是否還有下一個元素\n boolean hasNext();\n // 返回下一個元素\n E next();\n // 刪除迭代過程中最近訪問的一個元素\n // 也就是在next()之後調用remove()刪除剛剛next()返回的元素\n default void remove() {\n throw new UnsupportedOperationException(\"remove\");\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口是在"},{"type":"codeinline","content":[{"type":"text","text":"Java 1.5"}]},{"type":"text","text":"中引入的,爲了用來支持增強型"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環,只有實現了"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口的對象纔可以使用增強型"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環。"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口定義如下:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface Iterable {\n // 返回迭代器\n Iterator iterator();\n // 使用函數式接口對增強型for循環進行包裝,可以方便地使用lambda表達式來進行遍歷\n default void forEach(Consumer super T> action) {\n Objects.requireNonNull(action);\n for (T t : this) {\n action.accept(t);\n }\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口提供了"},{"type":"codeinline","content":[{"type":"text","text":"forEach"}]},{"type":"text","text":"方法的默認實現,函數參數是一個函數式接口"},{"type":"codeinline","content":[{"type":"text","text":"action"}]},{"type":"text","text":"參數來表示對遍歷到的每個元素的操作行爲,實現邏輯是使用 增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環 遍歷自身,循環中對每個元素都應用 參數"},{"type":"codeinline","content":[{"type":"text","text":"action"}]},{"type":"text","text":"所表示的操作行爲。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"遍歷List"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"List接口的定義"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"表示的是一個有序的元素集合。"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"接口繼承了"},{"type":"codeinline","content":[{"type":"text","text":"Collection"}]},{"type":"text","text":"接口,"},{"type":"codeinline","content":[{"type":"text","text":"Collection"}]},{"type":"text","text":"接口又繼承了"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口,其定義如下:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface Iterable {\n // 返回Iterator迭代器\n Iterator iterator();\n}\npublic interface Collection extends Iterable {\n}\npublic interface List extends Collection {\n // 獲取指定位置的元素\n E get(int index);\n // 獲取ListIterator迭代器\n ListIterator listIterator();\n // 從指定位置獲取ListIterator迭代器\n ListIterator listIterator(int index);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"除了可以通過"},{"type":"codeinline","content":[{"type":"text","text":"iterator()"}]},{"type":"text","text":"方法獲得"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器之外,還可以通過"},{"type":"codeinline","content":[{"type":"text","text":"listIterator()"}]},{"type":"text","text":"方法獲得"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"迭代器。"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"迭代器相比於"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器之外,訪問和操作元素的方法更加豐富:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"只能向後迭代,而"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"可以向兩個方向迭代"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"只能在迭代過程中刪除元素,而"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"可以添加元素、刪除元素、修改元素。"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface ListIterator extends Iterator {\n // Query Operations\n // 是否還有後一個元素\n boolean hasNext();\n // 訪問後一個元素\n E next();\n // 是否還有前一個元素\n boolean hasPrevious();\n // 訪問前一個元素\n E previous();\n // 後一個元素的下標\n int nextIndex();\n // 前一個元素的下標\n int previousIndex();\n\n // Modification Operations\n // 刪除元素\n void remove();\n // 修改元素\n void set(E e);\n // 添加元素 \n void add(E e);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"List的遍歷方法"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. 使用下標遍歷"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"接口提供了"},{"type":"codeinline","content":[{"type":"text","text":"get"}]},{"type":"text","text":"方法來訪問指定位置的元素,所以與遍歷數組一樣,"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"也可以通過遍歷"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"下標並使用"},{"type":"codeinline","content":[{"type":"text","text":"get"}]},{"type":"text","text":"方法訪問元素來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"for (int i = 0; i < list.size(); i++) {\n System.out.println(list.get(i));\n}"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. 使用Iterator迭代器"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"可以使用繼承自"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口的"},{"type":"codeinline","content":[{"type":"text","text":"iterator()"}]},{"type":"text","text":"方法來獲得"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器,使用"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Iterator iterator = list.iterator();\nwhile (iterator.hasNext()){\n System.out.println(iterator.next());\n}"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3. 使用ListIterator迭代器"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"還可以使用"},{"type":"codeinline","content":[{"type":"text","text":"listIterator()"}]},{"type":"text","text":"方法來獲得"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"迭代器,使用"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"迭代器來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"ListIterator listIterator = list.listIterator();\nwhile (listIterator.hasNext()){\n System.out.println(listIterator.next());\n}\n// ListIterator 可以向前遍歷\nlistIterator = list.listIterator(list.size() - 1);\nwhile (listIterator.hasPrevious()){\n System.out.println(listIterator.previous());\n}"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4. 增強for循環"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們前面說到,實現了"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口的對象可以使用增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環遍歷。"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"接口繼承自"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口,所以可以使用增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"for (Integer value : list) {\n System.out.println(value);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"增強性"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環是一種語法糖,但是與遍歷數組不一樣的是,使用增強型"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環在遍歷實現了"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口的對象時,會在編譯過程中將其轉化爲使用"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器進行遍歷的方式。所以這種方式本質上與上一種方式是一樣的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環語法更詳細的介紹,請移步:"},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2","title":""},"content":[{"type":"text","text":"Java Language Specification - 14.14.2. The enhanced for statement"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5. Iterable接口的forEach方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"List接口實現了"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口,"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口中提供了"},{"type":"codeinline","content":[{"type":"text","text":"forEach"}]},{"type":"text","text":"方法來更加方便的遍歷集合。其參數是一個函數式接口"},{"type":"codeinline","content":[{"type":"text","text":"action"}]},{"type":"text","text":",來表示對遍歷到的每個元素的操作行爲。並且因爲參數是一個函數式接口,所以我們可以使用"},{"type":"codeinline","content":[{"type":"text","text":"lamdba"}]},{"type":"text","text":"表達式更簡潔的表達遍歷過程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口的"},{"type":"codeinline","content":[{"type":"text","text":"forEach"}]},{"type":"text","text":"方法的默認實現是使用增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環來遍歷自身。所以如果沒有重寫"},{"type":"codeinline","content":[{"type":"text","text":"forEach"}]},{"type":"text","text":"方法的話,這種方式本質上與上一種方式是一樣的。"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"list.forEach(value -> System.out.println(value));\nlist.forEach(System.out::println);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"最佳實踐"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面幾種方式其實本質上來講只有兩種方式:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"使用循環遍歷集合的下標範圍,配合"},{"type":"codeinline","content":[{"type":"text","text":"get"}]},{"type":"text","text":"方法獲取集合元素 來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"使用迭代器("},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"或"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":")來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其餘方式都只不過是第二種方式的語法糖或其變種。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼到底應該使用哪種方式更好呢?這取決於"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"的內部實現方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"的常用實現數據結構有兩種,"},{"type":"codeinline","content":[{"type":"text","text":"數組"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"鏈表"}]},{"type":"text","text":":"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"對於數組實現的"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"及其對應的"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"實現來說,比如"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"Vector"}]},{"type":"text","text":"。"},{"type":"codeinline","content":[{"type":"text","text":"List.get()"}]},{"type":"text","text":"方法、"},{"type":"codeinline","content":[{"type":"text","text":"Iterator.next()"}]},{"type":"text","text":"方法、"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator.next()"}]},{"type":"text","text":"方法、"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator.previous()"}]},{"type":"text","text":"方法的時間複雜度都爲"},{"type":"codeinline","content":[{"type":"text","text":"O(1)"}]},{"type":"text","text":"。所以使用下標遍歷所有元素的時間複雜度爲"},{"type":"codeinline","content":[{"type":"text","text":"O(N)"}]},{"type":"text","text":",使用迭代器遍歷所有元素的時間複雜度也爲"},{"type":"codeinline","content":[{"type":"text","text":"O(N)"}]},{"type":"text","text":"。但是下標遍歷的方式執行的代碼更少更簡單,所以效率稍高。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"而對於鏈表實現的"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"其對應的"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"實現來說,"},{"type":"codeinline","content":[{"type":"text","text":"List.get()"}]},{"type":"text","text":"方法的時間複雜度爲"},{"type":"codeinline","content":[{"type":"text","text":"O(N)"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"Iterator.next()"}]},{"type":"text","text":"方法、"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator.next()"}]},{"type":"text","text":"方法、"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator.previous()"}]},{"type":"text","text":"方法的時間複雜度都爲"},{"type":"codeinline","content":[{"type":"text","text":"O(1)"}]},{"type":"text","text":"。所以使用下標遍歷所有元素的時間複雜度爲"},{"type":"codeinline","content":[{"type":"text","text":"O(N*N)"}]},{"type":"text","text":",使用迭代器遍歷所有元素的時間複雜度爲"},{"type":"codeinline","content":[{"type":"text","text":"O(N)"}]},{"type":"text","text":"。所以使用迭代器遍歷效率更高。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"集合框架中,提供了一個"},{"type":"codeinline","content":[{"type":"text","text":"RandomAccess"}]},{"type":"text","text":"接口,該接口沒有方法,只是一個標記。通常被"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"接口的實現類使用,用來標記該"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":"的實現類是否支持"},{"type":"codeinline","content":[{"type":"text","text":"Random Access"}]},{"type":"text","text":"。一個集合類實現了該接口,就意味着它支持"},{"type":"codeinline","content":[{"type":"text","text":"Random Access"}]},{"type":"text","text":",按位置讀取元素的平均時間複雜度爲"},{"type":"codeinline","content":[{"type":"text","text":"O(1)"}]},{"type":"text","text":",比如"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"。而沒有實現該接口的,就表示不支持"},{"type":"codeinline","content":[{"type":"text","text":"Random Access"}]},{"type":"text","text":",比如"},{"type":"codeinline","content":[{"type":"text","text":"LinkedList"}]},{"type":"text","text":"。所以推薦的做法就是,如果想要遍歷一個"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"如果其實現了"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"RandomAccess"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"接口,那麼使用下標遍歷效率更高,否則的話使用迭代器遍歷效率更高"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"遍歷Set"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Set接口的定義"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface Iterable {\n // 返回Iterator迭代器\n Iterator iterator();\n}\npublic interface Collection extends Iterable { }\npublic interface Set extends Collection { }"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Set的遍歷方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相較於"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":"是無序的,所以"},{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":"沒有通過下標獲取元素的"},{"type":"codeinline","content":[{"type":"text","text":"get"}]},{"type":"text","text":"方法,也就沒辦法使用下標來遍歷。"},{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":"也沒有類似"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"一樣特殊的迭代器。所以遍歷"},{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":"只能使用"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器來遍歷。下面三種方式其實本質上都是使用"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器來遍歷,後兩種方式只是第一種方式的語法糖或者變種。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. 使用Iterator迭代器"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":"接口同樣繼承了"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"iterator()"}]},{"type":"text","text":"方法,可以使用其返回的"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Iterator iterator = set.iterator();\nwhile (iterator.hasNext()){\n System.out.println(iterator.next());\n}"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. 增強for循環"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":"接口實現了"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口,所以也可以使用增強型"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"for (Integer value : set) {\n System.out.println(value);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3. Iterable接口的forEach方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":"接口實現了"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"接口,所以也可以使用"},{"type":"codeinline","content":[{"type":"text","text":"forEach"}]},{"type":"text","text":"方法來遍歷"},{"type":"codeinline","content":[{"type":"text","text":"Set"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"set.forEach(value -> System.out.println(value));\nset.forEach(System.out::println);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"遍歷Map"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不同於"},{"type":"codeinline","content":[{"type":"text","text":"List"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"Map"}]},{"type":"text","text":"並不是一組元素的集合,而是一組鍵值對,所以"},{"type":"codeinline","content":[{"type":"text","text":"Map"}]},{"type":"text","text":"沒有繼承"},{"type":"codeinline","content":[{"type":"text","text":"Collection"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"等其他接口。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Map接口的定義"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface Map {\n // 返回Map中鍵的集合\n Set keySet();\n // 返回Map中值的集合\n Collection values();\n // 返回Map中鍵值對的集合\n Set> entrySet();\n // 類似於Iterable接口的forEach方法\n default void forEach(BiConsumer super K, ? super V> action) {\n Objects.requireNonNull(action);\n for (Map.Entry entry : entrySet()) {\n K k;\n V v;\n try {\n k = entry.getKey();\n v = entry.getValue();\n } catch(IllegalStateException ise) {\n // this usually means the entry is no longer in the map.\n throw new ConcurrentModificationException(ise);\n }\n action.accept(k, v);\n }\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Map"}]},{"type":"text","text":"提供了"},{"type":"codeinline","content":[{"type":"text","text":"keySet()"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"values()"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"entrySet()"}]},{"type":"text","text":"方法來分別獲取"},{"type":"codeinline","content":[{"type":"text","text":"Map"}]},{"type":"text","text":"的 鍵集合、值集合、鍵值對集合。並且提供了類似於"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"forEach"}]},{"type":"text","text":"方法及其默認實現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Map的遍歷方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"遍歷"},{"type":"codeinline","content":[{"type":"text","text":"Map"}]},{"type":"text","text":"可以通過先獲取其 鍵集合、值集合、鍵值對集合,然後根據返回的集合類型選擇不同的遍歷方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同時,"},{"type":"codeinline","content":[{"type":"text","text":"Map"}]},{"type":"text","text":"也提供了類似於"},{"type":"codeinline","content":[{"type":"text","text":"Iterable"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"forEach"}]},{"type":"text","text":"方法,參數"},{"type":"codeinline","content":[{"type":"text","text":"action"}]},{"type":"text","text":"是一個函數式接口,指定了對於每一個鍵值對的操作行爲,實現邏輯是使用增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環遍歷"},{"type":"codeinline","content":[{"type":"text","text":"Map"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"entrySet()"}]},{"type":"text","text":"方法的返回值,對於每一個遍歷到的每一個鍵值對,應用參數"},{"type":"codeinline","content":[{"type":"text","text":"action"}]},{"type":"text","text":"代表的操作行爲。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"Java集合中的快速失敗機制"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"何爲快速失敗"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://en.wikipedia.org/wiki/Fail-fast","title":""},"content":[{"type":"text","text":"wikipedia"}]},{"type":"text","text":"上對"},{"type":"codeinline","content":[{"type":"text","text":"快速失敗(fail-fast)"}]},{"type":"text","text":"的介紹是:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"In systems design, a fail-fast system is one which immediately reports at its interface any condition that is likely to indicate a failure. Fail-fast systems are usually designed to stop normal operation rather than attempt to continue a possibly flawed process. "}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡單來說就是系統運行中,如果有錯誤發生,那麼系統立即結束,而不是繼續冒不確定的風險繼續執行,這種設計就是\""},{"type":"text","marks":[{"type":"strong"}],"text":"快速失敗"},{"type":"text","text":"\"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Java集合迭代器的快速失敗機制"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"集合框架中的一些集合類的迭代器也是被設計爲"},{"type":"codeinline","content":[{"type":"text","text":"快速失敗"}]},{"type":"text","text":"的。集合迭代器中的快速失敗機制是說:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在使用迭代器遍歷集合時,如果迭代器創建之後,通過 除了迭代器提供的修改方法之外 的其他方式對集合進行了結構性修改(添加、刪除元素等),那麼迭代器應該拋出一個"},{"type":"codeinline","content":[{"type":"text","text":"ConcurrentModificationException"}]},{"type":"text","text":"異常,表示在此次遍歷中集合發生了\"併發修改\",應該提前終止迭代過程。因爲在迭代器遍歷集合的過程中,如果有別的行爲改變了集合本身的結構,那麼迭代器之後的行爲可能就是不符合預期的,可能會出現錯誤的結果,所以提前檢測並拋出異常是一個更好的做法。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中大部分基本的集合類的迭代器都實現了快速失敗機制,包括"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"LinkedList"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"Vector"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"HashMap"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"HashSet"}]},{"type":"text","text":"等等。但是對於併發集合類,例如"},{"type":"codeinline","content":[{"type":"text","text":"ConcurrentHashMap"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"CopyOnWriteArrayList"}]},{"type":"text","text":"等,這些類本身就是設計來支持併發的,是線程安全的,所以也不存在快速失敗這一說。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"爲例,"},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html","title":""},"content":[{"type":"text","text":"ArrayList (Java Platform SE 8 )"}]},{"type":"text","text":"中對"},{"type":"codeinline","content":[{"type":"text","text":"fail-fast"}]},{"type":"text","text":"的介紹如下:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future."}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"iterator"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"listIterator"}]},{"type":"text","text":"方法返回的迭代器都是"},{"type":"codeinline","content":[{"type":"text","text":"fail-fast"}]},{"type":"text","text":"的:如果在迭代器創建之後,通過除了迭代器自身的"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"方法之外的其他方式,對"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"進行了結構性修改(添加、刪除元素等),那麼該迭代器應該拋出一個"},{"type":"codeinline","content":[{"type":"text","text":"ConcurrentModificationException"}]},{"type":"text","text":"異常。所以,迭代器在面對併發修改時,迭代器將快速而乾淨地失敗,而不是冒着在未來不確定的時間發生不確定行爲的風險繼續執行。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"典型實踐"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果看過阿里的《JAVA開發手冊》,會知道里面有這一條規範:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"【強制】不要在 "},{"type":"codeinline","content":[{"type":"text","text":"foreach"}]},{"type":"text","text":" 循環裏進行元素的 "},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":" 操作。"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":" 元素請使用 "},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"方式,如果併發操作,需要對 "},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":" 對象加鎖。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面說的"},{"type":"codeinline","content":[{"type":"text","text":"foreach"}]},{"type":"text","text":"循環指的上面我們提到的使用增強"},{"type":"codeinline","content":[{"type":"text","text":"for"}]},{"type":"text","text":"循環進行遍歷的方式。這種方式本質上使用的是迭代器方式。所以更明確一點,這個規範其實就是在說:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在使用"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"迭代器遍歷集合過程中,不要通過集合本身的"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":"方法來進行元素的 "},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":" 操作,"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"請使用"},{"type":"codeinline","content":[{"type":"text","text":"Iterator"}]},{"type":"text","text":"提供的"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"方法。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"正確"},{"type":"text","text":"方式:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"List list = new ArrayList<>();\nlist.add(1);\nlist.add(2);\nlist.add(3);\nIterator iterator = list.iterator();\nwhile (iterator.hasNext()) {\n Integer item = iterator.next();\n if (item == 1) {\n iterator.remove();\n }\n}\nlist.forEach(System.out::println); // 輸出 2 3 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"錯誤"},{"type":"text","text":"方式:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"List list = new ArrayList<>();\nlist.add(1);\nlist.add(2);\nlist.add(3);\nfor (Integer item : list) { // 會在這裏拋出異常\n if (item == 1) {\n list.remove(item); // 使用 list.remove 刪除\n }\n}\nlist.forEach(System.out::println);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述代碼會在第五行拋出"},{"type":"codeinline","content":[{"type":"text","text":"java.util.ConcurrentModificationException"}]},{"type":"text","text":"異常。因爲其本質還是使用迭代器遍歷,所以爲了方便理解其原因,我們將上述方式改寫爲:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"List list = new ArrayList<>();\nlist.add(1);\nlist.add(2);\nlist.add(3);\nIterator iterator = list.iterator();\nwhile (iterator.hasNext()) {\n Integer item = iterator.next(); // 會在這裏拋出異常\n if (item == 1) {\n list.remove(item); // 使用 list.remove 刪除\n }\n}\nlist.forEach(System.out::println);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這段代碼會在第"},{"type":"codeinline","content":[{"type":"text","text":"7"}]},{"type":"text","text":"行拋出"},{"type":"codeinline","content":[{"type":"text","text":"java.util.ConcurrentModificationException"}]},{"type":"text","text":"異常。與第一種方式的差別僅僅在於使用了"},{"type":"codeinline","content":[{"type":"text","text":"List.remove"}]},{"type":"text","text":"方法而不是"},{"type":"codeinline","content":[{"type":"text","text":"Iterator.remove"}]},{"type":"text","text":"方法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"快速失敗的實現原理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"爲例來說明快速失敗機制的實現原理,其他類的實現方式也是大致相同的。"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"中有一個屬性"},{"type":"codeinline","content":[{"type":"text","text":"modCount"}]},{"type":"text","text":",是一個記錄"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"修改次數的計數器。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"iterator"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"listIterator"}]},{"type":"text","text":"方法被調用時,會創建出"},{"type":"codeinline","content":[{"type":"text","text":"Iteartor"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"ListIterator"}]},{"type":"text","text":"的實現類 "},{"type":"codeinline","content":[{"type":"text","text":"ArrayList.Itr"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList.ListItr"}]},{"type":"text","text":"迭代器對象,其中有一個屬性"},{"type":"codeinline","content":[{"type":"text","text":"expectedModCount"}]},{"type":"text","text":"。當迭代器被創建時,"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"本身的"},{"type":"codeinline","content":[{"type":"text","text":"modCount"}]},{"type":"text","text":"將被複制給"},{"type":"codeinline","content":[{"type":"text","text":"Itr"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"ListItr"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"expectedModCount"}]},{"type":"text","text":"屬性。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"當使用迭代器的"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":"方法增刪元素時,在修改"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"modCount"}]},{"type":"text","text":"之後,還會將其值複製給迭代器自身的"},{"type":"codeinline","content":[{"type":"text","text":"expectedModCount"}]},{"type":"text","text":"。而通過"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":"方法增刪元素時,僅僅修改了"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"modCount"}]},{"type":"text","text":"。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"當迭代器執行"},{"type":"codeinline","content":[{"type":"text","text":"next"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"set"}]},{"type":"text","text":"操作時是會檢查迭代器自身的"},{"type":"codeinline","content":[{"type":"text","text":"expectedModCount"}]},{"type":"text","text":"與"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"modCount"}]},{"type":"text","text":"是否相等,如果不相等則會拋出"},{"type":"codeinline","content":[{"type":"text","text":"ConcurrentModificationException"}]},{"type":"text","text":"異常。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以在迭代過程中,如果只使用迭代器的"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":"方法增刪元素,是不會出現問題的,因爲在增刪元素之後迭代器始終會將"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"modCount"}]},{"type":"text","text":"值賦值給迭代器自身的"},{"type":"codeinline","content":[{"type":"text","text":"expectedModCount"}]},{"type":"text","text":",所以下次迭代兩者一定相等。而如果迭代過程中使用了"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"add"}]},{"type":"text","text":"方法增刪元素,或者有另外一個迭代器進行了增刪元素,就會造成"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"modCount"}]},{"type":"text","text":"與迭代器中的"},{"type":"codeinline","content":[{"type":"text","text":"expectedModCount"}]},{"type":"text","text":"不一致,拋出"},{"type":"codeinline","content":[{"type":"text","text":"ConcurrentModificationException"}]},{"type":"text","text":"異常。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"快速失敗的\"bug\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"快速失敗機制也不能夠保證百分之百生效,例如,在下面這段代碼中,使用迭代器遍歷"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"過程中,使用"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"remove"}]},{"type":"text","text":"方法刪除倒數第二個元素,程序能夠正確刪除,並不會像我們上面所說的拋出"},{"type":"codeinline","content":[{"type":"text","text":"ConcurrentModificationException"}]},{"type":"text","text":"異常。"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"List list = new ArrayList<>();\nlist.add(1);\nlist.add(2);\nlist.add(3);\nIterator iterator = list.iterator();\nwhile (iterator.hasNext()) {\n Integer item = iterator.next();\n if (item == 2) {\n list.remove(item);\n }\n}\nlist.forEach(System.out::println); // 輸出 1 3"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個\""},{"type":"codeinline","content":[{"type":"text","text":"bug"}]},{"type":"text","text":"\"發生的原因在於,在第二次執行"},{"type":"codeinline","content":[{"type":"text","text":"iterator.next()"}]},{"type":"text","text":"後,迭代器記錄的下一次將要訪問的下標應該是"},{"type":"codeinline","content":[{"type":"text","text":"2"}]},{"type":"text","text":",而在執行"},{"type":"codeinline","content":[{"type":"text","text":"list.remove()"}]},{"type":"text","text":"刪除元素後,"},{"type":"codeinline","content":[{"type":"text","text":"list"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"size"}]},{"type":"text","text":"變爲了"},{"type":"codeinline","content":[{"type":"text","text":"2"}]},{"type":"text","text":",所以在下次執行"},{"type":"codeinline","content":[{"type":"text","text":"iterator.hasNext()"}]},{"type":"text","text":"時認爲已經沒有元素要繼續迭代了,返回"},{"type":"codeinline","content":[{"type":"text","text":"false"}]},{"type":"text","text":",結束循環。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以"},{"type":"codeinline","content":[{"type":"text","text":"fail-fast"}]},{"type":"text","text":"機制並不能夠完全保證所有的併發修改的情況都拋出"},{"type":"codeinline","content":[{"type":"text","text":"ConcurrentModificationException"}]},{"type":"text","text":"異常,在程序中也不應該依賴於這個異常信息。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html","title":""},"content":[{"type":"text","text":"ArrayList (Java Platform SE 8 )"}]},{"type":"text","text":"中也指出了"},{"type":"codeinline","content":[{"type":"text","text":"fail-fast"}]},{"type":"text","text":"這一性質:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs."}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"參考"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2","title":""},"content":[{"type":"text","text":"The Java Language Specification, Java SE 8 Edition"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://blog.csdn.net/HJF_HUANGJINFU/article/details/51220253#t23","title":""},"content":[{"type":"text","text":"Java遍歷集合的幾種方法分析(實現原理、算法性能、適用場合)"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html","title":""},"content":[{"type":"text","text":"ArrayList (Java Platform SE 8 )"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章