Iterator迭代器,不可蜻蜓点水
对于java基础了解多少呢?对于Iterator迭代器,掌握多少嗯?是否真正会用了呢?
在做项目中,需求如下:后台传过来list对象,界面显示需要删除list的某一个对象。
解决办法如下:
第一种:其实后台直接传过来已经删除某个对象的list即可,在dao层的sql语句完成。界面直接循环list显示即可。
第二种:后台传过来完整的list对象,界面显示时,先删除list某一个对象,然后再循环显示删除后的list。
本人使用的是第二种做法,因为项目是分工开发的,后台已经完成并已封装。其实仔细思考后,没哟必要在后台再添加一个方法,直接在业务逻辑层中或action或jsp中再次加工而已。
list中删除一个对象,肯定是先遍历,然后找出不符合的,直接在集合中删除即可。
其中,java容器,Collection,Set,List,Map等等,这块,我曾经做过总结,感兴趣的可以浏览一下。当时做的总结,是把接口的分类,但没有涉及到其中的方法,add,remove,get等等。
首先看一下java代码:
public static void main(String[] args) { List c=new ArrayList(); c.add("测试迭代器"); c.add("测试java容器"); Iterator it=c.iterator(); while(it.hasNext()){ String test=(String)it.next(); if("测试java容器".equals(test)){ c.remove(test); } } System.out.println(c); }
这段java代码,看出猫腻了吗?乍一看,思路完全正确啊。那结果应该会输出[测试迭代器]呀。可以结果却不是如此。
执行这段java代码,抛出异常。
Exception in thread "main" java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(Unknown Source) at java.util.AbstractList$Itr.next(Unknown Source) at TestIterator.main(TestIterator.java:22)
产生错误的原因在于没有正确理解Iterator迭代器。
其实,迭代器是采用了快速失败的原理,一旦发现自己遍历的集合被修改,就像 c.remove(test);程序把集合c进行修改,则报以上的错误。其实这种错误经常在多线程中出现,一个线程在遍历集合,突然另一个线程把集合中的数据进行篡改。这种现象肯定是不允许出现的,报以上错误就是为了防止多线程共享资源发生资源争夺问题。
那如何避免这个问题呢?如何删除呢?
使用迭代器Iterator中的remove方法,Iterator迭代器一共三个方法,hasNext(),判断是否有下一个集合元素;Next(),返回的集合中下一个元素;remove()删除迭代器刚刚next的集合元素。
真正理解了这三个方法,使用就灰常简单了。
直接把c.remove(test);改成it.remove();即可。运行结果肯定必须也如愿以偿的是[测试迭代器];
另外在上述代码中进行改动一下,运行结果又是如何的呢?
public static void main(String[] args) { List c=new ArrayList(); c.add("测试迭代器"); c.add("测试java容器"); Iterator it=c.iterator(); while(it.hasNext()){ String test=(String)it.next(); if("测试java容器".equals(test)){ test="测试成功"; } } System.out.println(c); }
运行结果是[测试迭代器,测试java容器]。咦,为何没有发生变化呢?又得要重新理解Iterator迭代器了。
因为迭代器Iterator循环遍历集合元素时,并不是把集合元素给了迭代器变量test,而是把集合元素的值赋给了迭代器变量test,所以修改迭代器变量test的值时,并不是影响到集合元素。
这种情况就如值传参和引用传参。值传参,不会影响到原来的变量。而引用传参,则会影响到原来的变量,因为引用传参是指向的同一个内存区域。
通过这次异常,发现基础的重要性。同时也意识到,基础虽重要,理解也灰常重要。有些东西需要囫囵吞枣,走马观花,蜻蜓点水,不求甚解。但是有些东西必须做到咬文嚼字,耳熟能详,一清二楚,烂若披掌,了如指掌。