有关map中使用iterate迭代器遍历的不保序问题和list remove(object)的细节问题
今天在做项目的过程中发现了如下两个问题:
一 使用map的iterator迭代器对map进行遍历得到的结果是不保序的,也就是每次输出结果都是不一样的。针对这个问题,看以下iterator迭代器的源码。
二list的remove(Object obj) 和 removeAll()方法在删除的时候需要注意的几个地方。
上面两个问题都是比较细小的一些细节问题,但是如果基础知识不牢靠的话,那你在项目中如果使用到但是不知道这些问题,你有可能会遇到灾难性的后果。大家注意以下把。举个简单的例子,按照你的正常的逻辑你可能一直认为就是按照你想要的顺序进行遍历的,但是实际上却不是这样的。当你在项目中的时候,你会发现不知道怎么回事每次都得到不一样的结果,但是程序却没有任何异常。总之像这些比较细节,但是很考验功底的时候,我们不可能任何这种细节的问题都知道,但是每当我们遇到的时候都总结一下记住理解了就可以了。
好了下面针对这两个问题说一下吧。首先是第一个关于map 使用iterator迭代器遍历的时候不保序的问题。先上一个代码大家看看输出结果是什么。
Map<Integer, String> map = new HashMap<Integer, String>();
for(int i = 0;i<50;i++){
map.put(i, i+"");
}
Set<Entry<Integer, String>> iteratorSets = map.entrySet();
Iterator<Entry<Integer, String>> iterators=iteratorSets.iterator();
while (iterators.hasNext()) {
Entry<Integer, String> entry = iterators.next();
System.out.println("key :"+entry.getKey()); }
针对上面的这段代码,我们看看他两次的输出结果分别是:
key :0key :1key :2key :3key :4key :5key :6key :7key :8key :9key :10key :11key :12key :13key :14key :15key :17key :16key :19key :18key :21key :20key :23key :22key :25key :24key :27key :26key :29key :28key :31key :30key :34key :35key :32key :33key :38key :39key :36key :37key :42key :43key :40key :41key :46key :47key :44key :45key :49key :48
和key :0key :1key :2key :3key :4key :5key :6key :7key :8key :9key :10key :11key :12key :13key :14key :15key :17key :16key :19key :18key :21key :20key :23key :22key :25key :24key :27key :26key :29key :28key :31key :30key :34key :35key :32key :33key : 38key :39key :36key :37key :42key :43key :40key :41key :46key :47key :44key :45key :49key :48
从上面的两次的输出结果就可以看出来使用iterators迭代器是不能保证每次输出来的顺序的。当然先说一句,这里如果使用的是for来遍历这个map的话是没有问题的,因为for遍历的时候是从map的第一个元素进行遍历的。
知道了这个现象,那我们看一下map使用iterators进行迭代输出的时候为什么是不保序的,来看以下iterators的源码是怎么写的?
说道这个迭代器其实有研究过jdk中有关集合的源码的话,大家应该知道jdk中的集合有两种类型,一种是基于collection的,一种是基于map的,而基于collection这个集合接口的都是实现了iterator这个迭代器接口的,而这个iterator迭代器接口中只有三个方法,hasnext,next和iterator()返回iterator对象的方法。所以也就是说所有的实现了或者说基于collection接口的都有迭代器的功能。在这个迭代器中是如何对每一个具体的集合进行迭代的在方法中我们可以看到为什么是保序的了。
对于第二个问题。list remove()的删除中的一些细节的实现上需要注意的一些问题。说道这个remove,其实主要是想说一下在什么情况下回执行remove操作。在源代码中我们可以看到,如果是remove(int index)的话是没有问题的,因为是根据索引直接删除的。要说有问题的地方是如果要删除的事个对象的话在什么情况下回删除成功,好了直接说吧,就是在执行remove(object)的时候list默认会根据这个对象的equals()来判断当前要删除的对象是不是在这个集合中。这时候如果要删除的对象没有去显示的重写equals()方法的话,如果这个equals()方法是object默认的话是删除不掉的。我们先看看remove(object)这个源代码是怎么写的:
public boolean remove(Object o) {
if(o == null) {
for(intindex = 0; index < size; index++)
if(elementData[index] == null) {
fastRemove(index);
returntrue;
}
}else{
for(intindex = 0; index < size; index++)
if(o.equals(elementData[index])) {
fastRemove(index);
returntrue;
}
}
returnfalse;
}
在remove的源码中我们看到里面是有的事object的equals()方法来判断的,这个时候我们去看看默认的object中的equals()方法是如何是实现的:
public boolean equals(Object obj) {
return (this == obj);
}
熟悉java对象机制的应该都知道,这里其实是比较的两个对象的在内存中的地址是否相等,而不是比较的内容。所以如果你写如下这样的代码删除是不成功的
public static void main(String args []){
List<Student> students = new ArrayList<Student>();
for(int i = 0;i<10;i++){
Student student = new Student();
student.setName(i+"");
student.setAge(i);
students.add(student);
}
Student stu = new Student();
stu.setName(5+"");
students.remove(stu);
}
如果是这样想删除第五个元素的话是删除失败的,原因很简单,我们在student这个类中没有事重写equals()方法来重新定义判断是否相等的依据。如果我们想根据名称和年龄来判断是否相等可删除的话,需要重写student类的equals()方法。
public boolean equals(Object obj){
if(obj instanceof Student){
Student stu = obj;
if(stu.getName().equals(this.name) && stu.getAge().equals(this.age)){
return true;
}
} else {
return false;
}
}
这样的话相当于自定义了判断相等与否的规则。
上面两个比较细节的知识点,在使用的时候需要大家注意一下。这些虽然很细小确实考验功底的东西啊。好了对于这两个问题就总结到这里,下次再遇到再总结。
有关map中使用iterate迭代器遍历的不保序问题和list remove(object)的细节问题的更多相关文章
- Go map中一个很重要的特性
先看一段代码: func main() { m := make(map[int]string) m[1] = "a" m[2] = "b" m[3] = &qu ...
- JAVA中遍历Map和Set方法,取出map中所有的key
Java遍历Set集合 1.迭代器遍历: Set<String> set = new HashSet<String>(); Iterator<String> it ...
- 迭代器遍历【List、Set、Map】
迭代器遍历[List.Set.Map] example package boom.collection; import java.util.ArrayList; import java.util.Ha ...
- 获取map中的一个value值以及遍历map获得map里所有key、value的值
前言: 1.声明一个map: Map map = new HashMap();2.向map中放值,注意:map是key-value的形式存放的.如: map.put(”sa”,”dd”); 3.从ma ...
- Java List中迭代器遍历
在java中,List接口从Collection接口中继承了 iterator()函数,返回值是一个T类型的迭代器(泛型),T是List中元素的类型 public class TestListAndI ...
- java 迭代器遍历List Set Map
Iterator接口: 所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现Iterator接口的对象 Iterator对象称作为迭代器,用以方便的对容器内元素的遍历 ...
- 信1705-2 软工作业最大重复词查询思路: (1)将文章(一个字符串存储)按空格进行拆分(split)后,存储到一个字符串(单词)数组中。 (2)定义一个Map,key是字符串类型,保存单词;value是数字类型,保存该单词出现的次数。 (3)遍历(1)中得到的字符串数组,对于每一个单词,考察Map的key中是否出现过该单词,如果没出现过,map中增加一个元素,key为该单词,value为1(
通过学习学会了文本的访问,了解一点哈希表用途.经过网上查找做成了下面查询文章重复词的JAVA程序. 1 思 思路: (1)将文章(一个字符串存储)按空格进行拆分(split)后,存储到一个字符串(单词 ...
- Java 中List 集合索引遍历与迭代器遍历
package yzhou.iterator; import java.util.ArrayList; import java.util.HashSet; import java.util.Itera ...
- Map集合的应用及其遍历方式
---> HashMap :底层基于哈希表 存储原理也使用哈希表来存放的: 往HashMap添加了元素 ,首先会调用键的hashCode方法 获得一个哈希值,然后 ...
随机推荐
- Python3 与 C# 面向对象之~继承与多态 Python3 与 C# 面向对象之~封装 Python3 与 NetCore 基础语法对比(Function专栏) [C#]C#时间日期操作 [C#]C#中字符串的操作 [ASP.NET]NTKO插件使用常见问题 我对C#的认知。
Python3 与 C# 面向对象之-继承与多态 文章汇总:https://www.cnblogs.com/dotnetcrazy/p/9160514.html 目录: 2.继承 ¶ 2.1.单继 ...
- hdu 1081 & poj 1050 To The Max(最大和的子矩阵)
转载请注明出处:http://blog.csdn.net/u012860063 Description Given a two-dimensional array of positive and ne ...
- 构建基于Javascript的移动web CMS——Hello,World
在一篇构建基于Javascript的移动web CMS入门--简单介绍中简单的介绍了关于墨颀CMS的一些原理,其极框架组成.于是開始接着应该说明一下这个CMS是怎样一步步搭建起来. RequireJS ...
- cocos2d-x项目101次相遇:在HelloWorld上--建立新场景
cocos2d-x 101次相遇 / 文件夹 1 安装和环境搭建 -xcode 2 Scenes , Director, Layers, Sprites 3 建立图片菜单 4 在 ...
- 日常沟通的 3 种模式zz
一.日常沟通的 3 种模式 根据NLP (Neuro-Linguistic Programming,神经语言程序学),日常沟通的 3 种模式分别是:上堆.下切和平行,它们是什么意思呢? 1.上堆 意思 ...
- HDU 1418 抱歉 (欧拉公式)
[题目链接]:pid=1418">click here~~ [题目大意]: 假设平面上有n个点,而且每一个点至少有2条曲线段和它相连,就是说,每条曲线都是封闭的.同一时候,我们规定: ...
- 何时使用Entity或DTO
关注公众号: 锅外的大佬 每日推送国外优秀的技术翻译文章,励志帮助国内的开发者更好地成长! JPA和Hibernate允许你在JPQL和Criteria查询中使用DTO和Entity作为映射.当我在我 ...
- 宜人贷蜂巢API网关技术解密之Netty使用实践
一.背景 宜人贷蜂巢团队,由Michael创立于2013年,通过使用互联网科技手段助力金融生态和谐健康发展.自成立起一直致力于多维度数据闭环平台建设.目前团队规模超过百人,涵盖征信.电商.金融.社交. ...
- Jenkins + Maven + TestNG参数化调用测试用例
希望实现的场景:Jenkins中的Job可针对不同浏览器,不同环境,运行不同的测试用例集,但测试用例只保持一份. 具体实现的思路:在运行Jenkins Job时传入参数,运行 mvn test 命 ...
- 03 xml封装通信接口
<?php class Response_xml{ /** *按xml方式输出通信 *@param integet $code 状态码 *@param string $message 提示信息 ...