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}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章