遍历map的四种方法

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

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

 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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/190964.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • c语言数组详解(初学者这一篇就够了,看了不会打我)「建议收藏」

    c语言数组详解(初学者这一篇就够了,看了不会打我)「建议收藏」C语言数组详解1.数组:储存数据类型相同的一系列元素例如inta[100];在这里a数组储存100个int型元素,在这里[]这个符号就是告诉计算机a是一个数组。值得一提的是数组的下标访问数组的,数组中的a[0]一般表示你初始化的第一个值。2.初始化数组前面介绍过了,数组可以储存数据类型相同的一系列元素,所以初始化数组必不可少的一步就是告诉计算机这个数组储存的数据类型!…

  • format python保留小数点后几位_python四舍五入保留两位小数

    format python保留小数点后几位_python四舍五入保留两位小数print(“{:.2f}”.format(3.1415926))传送门

  • java webservice 实例

    java webservice 实例javawebservice实例 byhgwayen实验目的1.实现一个具有WebService功能的分布式对象类,能够实现求两个整数的最大值的功能。2.在另一台计算机(虚拟机)上,编写客户端程序,通过WebService技术访问远程的基于WebService的分布式对象Max,达到求两个整数的最大值的功能。一、创建并运行HelloWorldWebService.java。1.在classpath路径下新建/rs_midtest、/rs_

  • SM4 加密算法_des加密算法流程

    SM4 加密算法_des加密算法流程SM4加密算法密码算法中常用的一些数据单位:位/比特/bit:指一个二进制位。字节/byte:1字节=8位[公式]字/word:1字=4字节=32位[公式]SM4是一种分组密码算法,其分组长度为128位(即16字节,4字),密钥长度也为128位(即16字节,4字)。其加解密过程采用了32轮迭代机制(与DES、AES类似),每一轮需要一个轮密钥(与DES、AES类似)。加密过程分为两步,由32次轮迭代和1次反序变换组成。SM4的解密过程与加密过程完全相同,也包括32轮迭代和一次反序变换。只

  • pycharm开启自动补全_python代码补全插件

    pycharm开启自动补全_python代码补全插件在使用python时候我们可能更倾向于能够使用到自动补全代码的功能在一段时间的找寻和使用过程中,发现了几种能补全代码的插件和方法吧pycharm中TabNine插件 这个我感觉还能用吧~啧百度kite官网下载kite插件百度aiXcoder插件下载aiXcoder插件GitHub开源项目1.首先第一个TabNine的插件 亲测了一段时间,感觉很一般 如果想体验一下也不是不行 安装插件过程如下: pycharm编译器->File->Settings

  • pytest 执行用例_测试用例一般执行多少次

    pytest 执行用例_测试用例一般执行多少次前言平常我们功能测试用例非常多时,比如有1千条用例,假设每个用例执行需要1分钟,如果单个测试人员执行需要1000分钟才能跑完当项目非常紧急时,会需要协调多个测试资源来把任务分成两部分,于是执行时间

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号