转载请注明原创出处,谢谢!java
人生的大道上默默地走,就必需要有一盏灯亮着为你引导方向!而这盏灯抑或只是一句话,一句鼓励,一个赞美,一次认可,一次承认,一次相识一次交流……sql
上篇文章:阿里JAVA开发手册零度的思考理解(一)获得做者孤尽的确定支持,那是一个小激动啊,我会继续努力,继续阅读和思考阿里JAVA开发手册,毕竟每一条都是前人踩过的坑,经过血的教训总结出来的。数据库
看完这条,我的以为主要是集合相关操做,在JAVA基础中集合这块的重要性也的确很是重要(毕竟是用到最多的),本期只会结合上题进行一些简单扩展,并不会涵盖全部集合操做,也不涉及集合是否线程安全这块,后期我会在个人系列高并发、锁系列里扩展深刻。数组
已经有数组了为何会出现集合呢?依然清晰的记得数据结构里面顺序结构、链式结构的特色。在这里数组就属于顺序结构(可是集合里面根据顺序结构或者链式结构实现的都有,因此在选择用那个的时候最起码须要有那么一点点思考而不是拿什么用什么)。安全
数组一旦定义,长度将不能再变化。而且数组仅仅是一个一连串的变量而已,对于不少重复的操做(并无进行统一的抽象)并且有些顺序结构并不太适合,须要链式结构实现适合或者是须要顺序结构与链式结构结合实现才比较合适。微信
备注:对于不少重复的操做,好比若是须要扩容,须要本身实现,根据编码水平不一样实现的效率不同(并且这个可能大量存在,每一个人都须要实现,不符合工程学的思想),再好比须要排序,增删,遍历等等。数据结构
上面的一些问题就引入了集合而且解决了这些问题,因此集合很是重要,而且项目中集合处处可见,须要把db,nosql里面的数据接收下来。并发
下面看看集合具有的几个特性 :框架
集合遍历,从工程学咱们须要提供一种方法顺序访问一个集合对象中的各各元素,而又不须要暴露该对象的内部表示。nosql
如何才能作到呢??? 迭代器模式就能够作到,下面带你们一块儿去了解下。
迭代器模式的功能主要在于提供对聚合对象的迭代访问。主要就是这个访问进行作文章的。那么为何使用迭代器模式呢?有什么好处呢?
集合对象的类型不少,若是对集合对象的迭代访问跟集合对象自己融合在一块儿的话,会严重影响到集合对象的可扩展性和可维护性。
备注:迭代器模式的关键思想就是把对集合对象的遍历和访问从集合对象中分离出来,放到单独的迭代器中,这样集合对象会变得简单一些;而迭代器和集合对象能够独立的变化和发展,这样就大大加强类系统的灵活性。
通常状况下面,使用的都是外部迭代器(由客户端来控制迭代器的下一个元素的步骤,就是在代码里面咱们须要手动调用next来迭代下一个元素,这样作就是要灵活点)
备注:经过使用javap查看反编译代码,在数组里面,是固有的foreach实现,直接循环数组,而在容器的迭代foreach是经过迭代器来实现。
在稍微多作点铺垫
ArrayList对Iterator接口实现
备注:ArrayList里面对Iterator实现了2种,一种是普通的从前向后,而第二种是双向迭代输出,能够从往前也能够日后。
上面说了那么多,我以为如今能够开始解题了,各位看官久等了。并发系列又是另一个重要的话题,先不考虑并发进行分析,若是并发操做,须要对Iterator对象加锁,这个应该好理解。
This field is used by the iterator and list iterator implementation returned by the iterator and listIterator methods. If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or add operations. This provides fail-fast behavior, rather than non-deterministic behavior in the face of concurrent modification during iteration.
Use of this field by subclasses is optional. If a subclass wishes to provide fail-fast iterators (and list iterators), then it merely has to increment this field in its add(int, E) and remove(int) methods (and any other methods that it overrides that result in structural modifications to the list). A single call to add(int, E) or remove(int) must add no more than one to this field, or the iterators (and list iterators) will throw bogus ConcurrentModificationExceptions. If an implementation does not wish to provide fail-fast iterators, this field may be ignored.
因此应该注意,并不只仅包括remove,add元素也请使用Iterator方式。
这一条标准是加了强制的,说明了重要性,按照上面的优秀实践去作就对了。
public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); for(String item:list){ if("1".equals(item)){ //(1 换成 if("2".equals(item)){ list.remove(item); } } }
当(1 换成 if("2".equals(item)){ 以后,运行结果报异常,结果如图:
其实这种给出了错误,而且有代码行数的状况其实发现查找问题都挺方便的,其实该问题的重点就变成了都是基于Iterator的输出,可是在进行删除元素的时候应该用那种方式才正确。
没有必要纠结为何1不错,而2错,稍微看下源码就知道了,其实咱们也可让2不错,只是jdk里面就是这样实现的,它的解释和考虑以下缘由。
ArrayList此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在建立迭代器以后,除非经过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,不然在任什么时候间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException。所以,面对并发的修改,迭代器很快就会彻底失败,而不是冒着在未来某个不肯定时间发生任意不肯定行为的风险。
因此最佳实践就按照阿里java开发手册里面那样就行了,add元素也请使用Iterator方式。
可能说完,你们感受迭代器就仅仅在集合遍历里面用,并且都已经有了,其实实际中的确有一些用法,反正都是围绕控制访问的,好比分页,很是常见的状况,若是每次都基于数据库分页那么怕性能很差,若是彻底在内存(内存太贵,数据太多,不现实),通常的作法就是好比一页20条数据,咱们通常能够每次查询数据库的时候取5页到内存(具体每次取多少能够根据用户行为分析,获得一个比较合理的,并且越到后面访问的机会越少,取到内存的就越少了,能够先好比每次都是取n页数据,在多少页以后每次取m页 以后在每次取一页一页了。n>m>1)。那么好比取出来的100条数据在内存中,须要进行根据分页访问,而原来的jdk里面的好像不知足,那么本身实现一个相似的是否是特别灵活呢?后续有空,我会在个人微信公众号,系列文章的技术思考里面把相似这块分析下的。
这是阿里JAVA开发手册其中一条明细,期待你的留言和分析!!!
若是读完以为有收获的话,欢迎点赞加关注。
查阅更多历史,欢迎关注我的公众号!!!