今天在做项目的过程中发现了如下两个问题:

一 使用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)的细节问题的更多相关文章

  1. Go map中一个很重要的特性

    先看一段代码: func main() { m := make(map[int]string) m[1] = "a" m[2] = "b" m[3] = &qu ...

  2. JAVA中遍历Map和Set方法,取出map中所有的key

    Java遍历Set集合 1.迭代器遍历: Set<String> set = new HashSet<String>(); Iterator<String> it ...

  3. 迭代器遍历【List、Set、Map】

    迭代器遍历[List.Set.Map] example package boom.collection; import java.util.ArrayList; import java.util.Ha ...

  4. 获取map中的一个value值以及遍历map获得map里所有key、value的值

    前言: 1.声明一个map: Map map = new HashMap();2.向map中放值,注意:map是key-value的形式存放的.如: map.put(”sa”,”dd”); 3.从ma ...

  5. Java List中迭代器遍历

    在java中,List接口从Collection接口中继承了 iterator()函数,返回值是一个T类型的迭代器(泛型),T是List中元素的类型 public class TestListAndI ...

  6. java 迭代器遍历List Set Map

    Iterator接口: 所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现Iterator接口的对象 Iterator对象称作为迭代器,用以方便的对容器内元素的遍历 ...

  7. 信1705-2 软工作业最大重复词查询思路: (1)将文章(一个字符串存储)按空格进行拆分(split)后,存储到一个字符串(单词)数组中。 (2)定义一个Map,key是字符串类型,保存单词;value是数字类型,保存该单词出现的次数。 (3)遍历(1)中得到的字符串数组,对于每一个单词,考察Map的key中是否出现过该单词,如果没出现过,map中增加一个元素,key为该单词,value为1(

    通过学习学会了文本的访问,了解一点哈希表用途.经过网上查找做成了下面查询文章重复词的JAVA程序. 1 思 思路: (1)将文章(一个字符串存储)按空格进行拆分(split)后,存储到一个字符串(单词 ...

  8. Java 中List 集合索引遍历与迭代器遍历

    package yzhou.iterator; import java.util.ArrayList; import java.util.HashSet; import java.util.Itera ...

  9. Map集合的应用及其遍历方式

    ---> HashMap :底层基于哈希表      存储原理也使用哈希表来存放的:            往HashMap添加了元素 ,首先会调用键的hashCode方法 获得一个哈希值,然后 ...

随机推荐

  1. ElasticSearchserver操作命令

    在win7环境,进入elasticsearch安装文件夹的bin文件夹: 1. elasticsearch.bat 就能够启动elasticsearch了.执行这个插件的优点是:elasticsear ...

  2. Android pull to Refresh 导入出错?

    今天在导入 PuultoResfresh 的时候老是出错. error: [2014-09-28 10:04:44 - library] Unable to resolve target 'andro ...

  3. 开关电路_MOS和三极管

    https://blog.csdn.net/acelit/article/details/70171312 绍过一般的电源开关电路,控制电源的目的是省电,控制静态电流.不过以下的电路存在着几个缺点:  ...

  4. Layout规则总结

    一.尺寸要求 1.过孔到焊盘的距离多少合适? 6mil左右 2.铜皮到边框的距离多少合适? 极限8mil,通常12,最好做到20,40 3.Thermal焊盘打地孔个数? 正方形 3*3  4*4   ...

  5. Linux 中权限控制实例

    前言 前文对 Linux 中的权限进行了较为透彻的分析.而本文,则在前文的基础上,具体说明如何在代码中进行权限控制. 下面的代码涉及到以下几个方面: 1. 创建文件时设置文件权限 2. 修改文件的默认 ...

  6. 【BZOJ3197】[Sdoi2013]assassin 树同构+动态规划+KM

    [BZOJ3197][Sdoi2013]assassin Description Input Output Sample Input 4 1 2 2 3 3 4 0 0 1 1 1 0 0 0 Sam ...

  7. ThinkPHP 静态页缓存

    通过对ThinkPHP的学习,记录下静态页的缓存步骤,以便以后查阅: 1.配置配置文件/Admin/Conf/config.php代码如下: /*静态缓存*/ 'HTML_CACHE_ON'=> ...

  8. include vector 编译出错VC++

    error C2665: “operator new” : 5个重载中没有一个可以转换参数1(从“const char [71]”类型)这个错误是怎么回事啊,搜索了整个项目好像没有可疑的new操作阿. ...

  9. 网络测试常用的命令-比较ping,tracert和pathping等命令之间的关系

    无论你是一个网络维护人员,还是正在学习TCP/IP协议,了解和掌握一些常用的网络测试命令将会有助于您更快地检测到网络故障所在,同时也会有助你您了解网络通信的内幕. 下面我们逐步介绍几个常用的命令: 1 ...

  10. Android应用资源---动画资源(Animation Resources)

    有两种类型的动画资源: 属性动画 在设定的时间内,通过修改与Animator类相关的对象的属性值来创建一个动画. 视图动画 有两种类型的视图动画框架 补间动画(Tween animation):通过执 ...