遍历map的四种方法_北方的狼6775的博客-程序员宝宝_遍历map

技术标签: java  

 Map.entrySet() 这个方法返回的是一个Set<Map.Entry<K,V>>,Map.Entry 是Map中的一个接口,他的用途是表示一个映射项(里面有Key和Value),而Set<Map.Entry<K,V>>表示一个映射项的Set。Map.Entry里有相应的getKey和getValue方法,即JavaBean,让我们能够从一个项中取出Key和Value。

 

下面是遍历Map的四种方法:

public static void main(String[] args) {
 
 
  Map<String, String> map = new HashMap<String, String>();
  map.put("1", "value1");
  map.put("2", "value2");
  map.put("3", "value3");
  
  //第一种:普遍使用,二次取值
  System.out.println("通过Map.keySet遍历key和value:");
  for (String key : map.keySet()) {
   System.out.println("key= "+ key + " and value= " + map.get(key));
  }
  
  //第二种
  System.out.println("通过Map.entrySet使用iterator遍历key和value:");
  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
  while (it.hasNext()) {
   Map.Entry<String, String> entry = it.next();
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }
  
  //第三种:推荐,尤其是容量大时
  System.out.println("通过Map.entrySet遍历key和value");
  for (Map.Entry<String, String> entry : map.entrySet()) {
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }
 
  //第四种
  System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
  for (String v : map.values()) {
   System.out.println("value= " + v);
  }
 }


下面是HashMap的源代码:

首先HashMap的底层实现用的时候一个Entry数组


   
    
  1. java] view plain copy
  2. <pre name= "code" class= "java"> /**
  3. * The table, resized as necessary. Length MUST Always be a power of two.
  4. */
  5. transient Entry[] table; //声明了一个数组
  6. ........
  7. public HashMap() {
  8. this.loadFactor = DEFAULT_LOAD_FACTOR;
  9. threshold = ( int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
  10. table = new Entry[DEFAULT_INITIAL_CAPACITY]; //初始化数组的大小为DEFAULT_INITIAL_CAPACITY(这里是16)
  11. init();
  12. }</pre><br>


再来看一下Entry是在什么地方定义的,继续上源码,我们在HashMap的源码的674行发现了它的定义,原来他是HashMap的一个内部类,并且实现了Map.Entry接口,以下有些地方是转载安静

 


   
    
  1. static class Entry<K,V> implements Map. Entry<K,V> {
  2. final K key;
  3. V value;
  4. Entry<K,V> next;
  5. final int hash;
  6. /**
  7. * Creates new entry.
  8. */
  9. Entry(int h, K k, V v, Entry<K,V> n) {
  10. value = v;
  11. next = n;
  12. key = k;
  13. hash = h;
  14. }
  15. public final K getKey( ) {
  16. return key;
  17. }
  18. public final V getValue( ) {
  19. return value;
  20. }
  21. public final V setValue( V newValue) {
  22. V oldValue = value;
  23. value = newValue;
  24. return oldValue;
  25. }
  26. public final boolean equals( Object o) {
  27. if (!(o instanceof Map. Entry))
  28. return false;
  29. Map. Entry e = ( Map. Entry)o;
  30. Object k1 = getKey();
  31. Object k2 = e. getKey();
  32. if (k1 == k2 || (k1 != null && k1. equals(k2))) {
  33. Object v1 = getValue();
  34. Object v2 = e. getValue();
  35. if (v1 == v2 || (v1 != null && v1. equals(v2)))
  36. return true;
  37. }
  38. return false;
  39. }
  40. public final int hashCode( ) {
  41. return (key== null ? 0 : key. hashCode()) ^
  42. (value== null ? 0 : value. hashCode());
  43. }
  44. public final String toString( ) {
  45. return getKey() + "=" + getValue();
  46. }
  47. /**
  48. * This method is invoked whenever the value in an entry is
  49. * overwritten by an invocation of put(k,v) for a key k that's already
  50. * in the HashMap.
  51. */
  52. void recordAccess( HashMap<K,V> m) {
  53. }
  54. /**
  55. * This method is invoked whenever the entry is
  56. * removed from the table.
  57. */
  58. void recordRemoval( HashMap<K,V> m) {
  59. }
  60. }

 

既然这样那我们再看一下Map.Entry这个接口是怎么定义的,原来他是Map的一个内部接口并且定义了一些方法​​​​​​​


   
    
  1. interface Entry<K,V> {
  2. /**
  3. * Returns the key corresponding to this entry.
  4. *
  5. * @return the key corresponding to this entry
  6. * @throws IllegalStateException implementations may, but are not
  7. * required to, throw this exception if the entry has been
  8. * removed from the backing map.
  9. */
  10. K getKey();
  11. /**
  12. * Returns the value corresponding to this entry. If the mapping
  13. * has been removed from the backing map (by the iterator's
  14. * <tt>remove</tt> operation), the results of this call are undefined.
  15. *
  16. * @return the value corresponding to this entry
  17. * @throws IllegalStateException implementations may, but are not
  18. * required to, throw this exception if the entry has been
  19. * removed from the backing map.
  20. */
  21. V getValue();
  22. /**
  23. * Replaces the value corresponding to this entry with the specified
  24. * value (optional operation). (Writes through to the map.) The
  25. * behavior of this call is undefined if the mapping has already been
  26. * removed from the map (by the iterator's <tt>remove</tt> operation).
  27. *
  28. * @param value new value to be stored in this entry
  29. * @return old value corresponding to the entry
  30. * @throws UnsupportedOperationException if the <tt>put</tt> operation
  31. * is not supported by the backing map
  32. * @throws ClassCastException if the class of the specified value
  33. * prevents it from being stored in the backing map
  34. * @throws NullPointerException if the backing map does not permit
  35. * null values, and the specified value is null
  36. * @throws IllegalArgumentException if some property of this value
  37. * prevents it from being stored in the backing map
  38. * @throws IllegalStateException implementations may, but are not
  39. * required to, throw this exception if the entry has been
  40. * removed from the backing map.
  41. */
  42. V setValue(V value);
  43. /**
  44. * Compares the specified object with this entry for equality.
  45. * Returns <tt>true</tt> if the given object is also a map entry and
  46. * the two entries represent the same mapping. More formally, two
  47. * entries <tt>e1</tt> and <tt>e2</tt> represent the same mapping
  48. * if<pre>
  49. * (e1.getKey()==null ?
  50. * e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&
  51. * (e1.getValue()==null ?
  52. * e2.getValue()==null : e1.getValue().equals(e2.getValue()))
  53. * </pre>
  54. * This ensures that the <tt>equals</tt> method works properly across
  55. * different implementations of the <tt>Map.Entry</tt> interface.
  56. *
  57. * @param o object to be compared for equality with this map entry
  58. * @return <tt>true</tt> if the specified object is equal to this map
  59. * entry
  60. */
  61. boolean equals( Object o);
  62. /**
  63. * Returns the hash code value for this map entry. The hash code
  64. * of a map entry <tt>e</tt> is defined to be: <pre>
  65. * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^
  66. * (e.getValue()==null ? 0 : e.getValue().hashCode())
  67. * </pre>
  68. * This ensures that <tt>e1.equals(e2)</tt> implies that
  69. * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries
  70. * <tt>e1</tt> and <tt>e2</tt>, as required by the general
  71. * contract of <tt>Object.hashCode</tt>.
  72. *
  73. * @return the hash code value for this map entry
  74. * @see Object#hashCode()
  75. * @see Object#equals(Object)
  76. * @see #equals(Object)
  77. */
  78. int hashCode();
  79. }

 


     看到这里的时候大伙儿估计都明白得差不多了为什么HashMap为什么要选择Entry数组来存放key-value对了吧,因为Entry实现的Map.Entry接口里面定义了getKey(),getValue(),setKey(),setValue()等方法相当于一个javaBean,对键值对进行了一个封装便于后面的操作,从这里我们其实也可以联想到不光是HashMap,譬如LinkedHashMap,TreeMap 等继承自map的容器存储key-value对都应该使用的是Entry只不过组织Entry的形式不一样,HashMap用的是数组加链表的形式,LinkedHashMap用的是链表的形式,TreeMap应该使用的二叉树的形式,不信的话上源码

 

LinkedHashMap:​​​​​​​


   
    
  1. /**
  2. * The head of the doubly linked list.
  3. */
  4. /定义了链头
  5. private transient Entry<K,V> header;

 


初始化链表的方法:


   
    
  1. void init( ) {
  2. header = new Entry<K,V>(- 1, null, null, null);
  3. header. before = header. after = header;
  4. }

​​​​​​

TreeMap:


   
    
  1. [ java] view plain copy
  2. //定义根节点
  3. private transient Entry<K,V> root = null;

​​​​​​​

再看他的put方法,是不是很面熟(二叉排序树的插入操作)​​​​​​​


   
    
  1. public V put( K key, V value) {
  2. Entry<K,V> t = root;
  3. if (t == null) {
  4. // TBD:
  5. // 5045147: (coll) Adding null to an empty TreeSet should
  6. // throw NullPointerException
  7. //
  8. // compare(key, key); // type check
  9. root = new Entry<K,V>(key, value, null);
  10. size = 1;
  11. modCount++;
  12. return null;
  13. }
  14. int cmp;
  15. Entry<K,V> parent;
  16. // split comparator and comparable paths
  17. Comparator<? super K> cpr = comparator;
  18. if (cpr != null) {
  19. do {
  20. parent = t;
  21. cmp = cpr. compare(key, t. key);
  22. if (cmp < 0)
  23. t = t. left;
  24. else if (cmp > 0)
  25. t = t. right;
  26. else
  27. return t. setValue(value);
  28. } while (t != null);
  29. }
  30. else {
  31. if (key == null)
  32. throw new NullPointerException();
  33. Comparable<? super K> k = ( Comparable<? super K>) key;
  34. do {
  35. parent = t;
  36. cmp = k. compareTo(t. key);
  37. if (cmp < 0)
  38. t = t. left;
  39. else if (cmp > 0)
  40. t = t. right;
  41. else
  42. return t. setValue(value);
  43. } while (t != null);
  44. }
  45. Entry<K,V> e = new Entry<K,V>(key, value, parent);
  46. if (cmp < 0)
  47. parent. left = e;
  48. else
  49. parent. right = e;
  50. fixAfterInsertion(e);
  51. size++;
  52. modCount++;
  53. return null;
  54. }

 


ok,明白了各种Map的底层存储key-value对的方式后,再来看看如何遍历map吧,这里用HashMap来演示吧

 

 Map提供了一些常用方法,如keySet()、entrySet()等方法,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。

so,很容易写出如下的遍历代码​​​​​​​


   
    
  1. [java] view plain copy
  2. 1. Map map = new HashMap();
  3. Irerator iterator = map.entrySet().iterator();
  4. while(iterator.hasNext()) {
  5. Map. Entry entry = iterator.next();
  6. Object key = entry.getKey();
  7. //
  8. }
  9. 2. Map map = new HashMap();
  10. Set keySet= map.keySet();
  11. Irerator iterator = keySet.iterator;
  12. while(iterator.hasNext()) {
  13. Object key = iterator.next();
  14. Object value = map.get(key);
  15. //
  16. }
  17. 另外,还有一种遍历方法是,单纯的遍历value值,Map有一个values方法,返回的是value的Collection集合。通过遍历collection也可以遍历value,如
  18. [java] view plain copy
  19. Map map = new HashMap();
  20. Collection c = map.values();
  21. Iterator iterator = c.iterator();
  22. while(iterator.hasNext()) {
  23. Object value = iterator.next();

 


原文转至:https://blog.csdn.net/kyi_zhu123/article/details/52769469

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_48358336/article/details/121078501

智能推荐

Maven企业级应用(四) 之依赖管理机制_喵了个汪q的博客-程序员宝宝_企业maven依赖管理

1、依赖引入的方式可以用如下方式引入依赖&lt;dependency&gt; &lt;groupId&gt;&lt;/groupId&gt; &lt;artifactId&gt;&lt;/artifactId&gt; &lt;version&gt;&lt;/version&gt; &lt;type&gt;&lt;/type&gt; &lt;scope&gt;&lt;/scope&gt; &lt;optional&gt;&lt;/optional&gt;&lt;/dependency&gt;

ORA-01008: not all variables bound_lijun123123的博客-程序员宝宝

ORA-01008: not all variables bound ORA-01008: not all variables bound 这个异常是因为SQL语句中的 ? 没有被传参数导致的。

Elasticsearch 实战(一、基本概念与安装使用)_绿水本无忧d的博客-程序员宝宝

Elasticsearch作用: 快速存储、搜索和分析海量数据。基本概念Index 索引: 类似 MySQL 中的 Insert,指插入(索引)一条数据;也可以类似为 MySQL 中的 Database,一个数据库(索引)。Type: 类似于 MySQL 中的 table,可以理解成一张表(一个类型)。Document: 一条记录,以 json 格式存储。安装使用 Docker 安装命令中含有注释,请勿直接复制粘贴下载docker pull elasticsearch:7.4.2配

每个程序员都应该学习的5种编程语言_weixin_43875545的博客-程序员宝宝

了解一种或者真正的编码语言是很好的,但作为一个真正的多语言开发人员是如何实现真正的主要状态。我在某处读到程序员应该每年学习一种新的编程语言(我认为它的代码完整,但不确定),但如果你不能这样做,我建议你至少学习以下五种编程语言,以便在你的职业生涯中取得好成绩。 。每个公司都喜欢多语言程序员和一个全面的编码人员,他们是多才多艺的语言编写快速脚本,并且还可以编写复杂的Java程序,确实是一个有价值的...

Davies-Bouldin指数(DBI)_Rainylt的博客-程序员宝宝_dbi指数matlab代码

参考http://blog.sina.com.cn/s/blog_65c8baf901016flh.html用途:聚类算法中评估判断簇的个数是否合适(用来选择k)原理:计算所有簇的类内距离和类间距离的比值(类内/类间),比值越小越好。即希望类间距离越大,类内距离越小(数据越集中)越好公式:(1)分散度(类内距离)Si:表示第i个类中,度量数据点的分散程度(2)类间距离Mij:表示第i类中心与第j类中心的距离(3)两类的相似度:其实就是分散度/类间距离越分散,类间距离越小,相似度越大(

android拍照功能无预览,Android快速实现无预览拍照功能_杯中水8033的博客-程序员宝宝

Android快速实现无预览拍照功能camerakit:ckFacing="front" 表示用前置摄像头,其他属性请参照官方文档。注意:宽高不能设置为0,否则不能拍照。3、Java代码public class MainActivity extends BaseActivity {@BindView(R.id.btn_test)Button btnTest;@BindView(R.id.camer...

随便推点

Python调用外部程序——os.system()和subprocess.call_ailsa0503的博客-程序员宝宝

通过os.system函数调用其他程序预备知识:cmd中打开和关闭程序cmd中打开程序a.打开系统自带程序系统自带的程序的路径一般都已加入环境变量之中,只需在cmd窗口中直接输入程序名称即可。以notepad为例,直接在cmd窗口中输入notepad后回车即可打开。b.打开自己安装且没有加入环境变量的程序以网易云音乐为例...

Android5.0,6.0,7.0,8.0新特性整理_感同身受ing的博客-程序员宝宝

转Android5.0,6.0,7.0,8.0新特性整理2017年08月31日 00:01:00 锐心凌志 阅读数:9654更多个人分类: Android背景Android5.0(Android Lollipop)是谷歌公司2014年10月发布的全新安卓系统,至今已经两年多。然而由于国产手机对安卓ROM的深度定制或修改,以及手机厂商、芯片制造商、运营商之间错综复杂的关系,我们更...

IOS集成支付宝回调的坑_kingtaxin的博客-程序员宝宝

最近做个项目需要集成支付,当然选用支付宝,但是过程中发现了巨大的坑支付完成后,在appdelegate中作回调,但是这个是不会执行- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:

python和tkinter实现摄像头实时无闪烁显示_zeroty的博客-程序员宝宝_python tkinter 摄像头

摄像头显示者tkinter段canvas中很简单,但要无闪烁,就要弄很久。后来,发现,其实就一句话,也不知道为啥,反正在creat_image之后,加上obr就可以,即类似:canvas_img.create_image(0, 0, anchor = NW ,image = cam_imageTk) obr = cam_imageTk 不多说了,上全部代码:from tkinter import *import tkinter as tkfrom PIL import

桐花万里python路-高级篇-并发编程-03-线程_weixin_30340819的博客-程序员宝宝

理论进程只是一个资源单位,线程才是cpu上的执行单位无需申请空间,创建开销小共享和创建开销多线程共享一个进程的地址空间线程比进程更轻量级,线程比进程更容易创建可撤销I/O密集型,多线程,会加快程序执行的速度在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)线程操作...

Luogu1525 关押罪犯_ShadyPi的博客-程序员宝宝

原题链接:https://www.luogu.org/problemnew/show/P1525关押罪犯题目描述SSS城现有两座监狱,一共关押着NNN名罪犯,编号分别为1−N1-N1−N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名...

推荐文章

热门文章

相关标签