Java HashMap遍历实践

来源:互联网 发布:我国的政治体制知乎 编辑:程序博客网 时间:2024/06/10 15:54

在原始记忆中,Java HashMap遍历,无非是for each或者iterator,但至于在遍历时性能如何,优缺点如何,泛泛而不得知。对于这样的基础问题,对于王二(Java编程6年,幸好我的方向不是编程)我来说,似乎羞于提及,但事实证明,我还必须“积硅步”。

①方法一、iterator迭代keys并搜索values

该种方法是我使用最频繁的,没有之一,详见如下代码:

<code class="language-java hljs  has-numbering">Map<Integer, Integer> map = <span class="hljs-keyword">new</span> HashMap<Integer, Integer>();addMap(map);<span class="hljs-keyword">long</span> t1 = System.currentTimeMillis();Iterator<Integer> keys = map.keySet().iterator();<span class="hljs-keyword">while</span> (keys.hasNext()) {    Integer key = keys.next();    Integer value = map.get(key);    keys.remove();}<span class="hljs-keyword">long</span> t2 = System.currentTimeMillis();System.out.println(<span class="hljs-string">"map.keySet().iterator()耗时:"</span> + (t2 - t1));</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>

以前的我看来,该种方法使用起来相当简洁,通过iterator遍历出来keys,然后通过key从map中获取对应的value,似乎也非常接地气。但是,弊端就在于

它更慢更低效,通过key得到value值更耗时(这个方法在所有实现map接口的map中比方法#1慢20%-200%)。如果你安装了FindBugs,它将检测并警告你这是一个低效的迭代。这个方法应该避免

看到这条信息,我是觉得有点唐突,怎么原来最喜欢的一种map遍历方式竟然如此low,简直让人失望。后面我会对花费的性能时间做一个统计,稍候关注。

②方法二、Iterator迭代Entry

这种方法我以前几乎不用,但方法二却有其关键的优点:

  1. 可以通过iterator对map的元素进行删除。方法一同样。
  2. 性能优良。
<code class="language-java hljs  has-numbering">Map<Integer, Integer> map = <span class="hljs-keyword">new</span> HashMap<Integer, Integer>();addMap(map);<span class="hljs-keyword">long</span> t3 = System.currentTimeMillis();Iterator<Entry<Integer, Integer>> entrys = map.entrySet().iterator();<span class="hljs-keyword">while</span> (entrys.hasNext()) {    Entry<Integer, Integer> entry = entrys.next();    Integer key = entry.getKey();    Integer value = entry.getValue();    entrys.remove();}<span class="hljs-keyword">long</span> t4 = System.currentTimeMillis();System.out.println(<span class="hljs-string">" map.entrySet().iterator()耗时:"</span> + (t4 - t3));</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>

通过“map.entrySet().iterator()”获得map的entry对象,然后通过getKey,getValue进行key和value值得获取,非常的直白和实用。

③方法三:For-Each迭代keys和values

for each一个局限是不同remove map中的元素,但遍历map还是非常好的。

<code class="language-java hljs  has-numbering">Map<Integer, Integer> map = <span class="hljs-keyword">new</span> HashMap<Integer, Integer>();addMap(map);<span class="hljs-keyword">long</span> t5 = System.currentTimeMillis();<span class="hljs-keyword">for</span> (Integer key : map.keySet()) {}<span class="hljs-keyword">for</span> (Integer value : map.values()) {}<span class="hljs-keyword">long</span> t6 = System.currentTimeMillis();System.out.println(<span class="hljs-string">"for each map.keySet()、map.values()耗时:"</span> + (t6 - t5));</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

不过这里,王二有话要说,按照stackoverflow上所说,该种方法要比接下来说的第四种方法“For-Each迭代entries”性能更好(大约快10%),但在我的实践中并非如此,这种方法反而比第四种“For-Each迭代entries”慢得多。

④方法四:For-Each迭代entries

<code class="language-java hljs  has-numbering">Map<Integer, Integer> map = <span class="hljs-keyword">new</span> HashMap<Integer, Integer>();addMap(map);<span class="hljs-keyword">long</span> t7 = System.currentTimeMillis();<span class="hljs-keyword">for</span> (Entry<Integer, Integer> entry : map.entrySet()) {    Integer key = entry.getKey();    Integer value = entry.getValue();}<span class="hljs-keyword">long</span> t8 = System.currentTimeMillis();System.out.println(<span class="hljs-string">"for each map.entrySet()耗时:"</span> + (t8 - t7));</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

这种方法就不多做介绍了。

⑤性能时间表

次序iterator迭代keys并搜索valuesIterator迭代EntryFor-Each迭代keys和valuesFor-Each迭代entries1耗时:37耗时:32耗时:39耗时:132耗时:29耗时:18耗时:32耗时:153耗时:50耗时:57耗时:39耗时:214耗时:47耗时:31耗时:39耗时:14

可以总结如下:

  1. 迭代keys并搜索values 非常低效,排名几乎在倒数第一或第二
  2. For-Each迭代entries 性能最佳,但无法remove
  3. For-Each迭代keys和values并没有比For-Each迭代entries 性能(大约快10%),stackoverflow上的数据也不能全部苟同
  4. Iterator迭代Entry 的方案显然最适合使用,性能优良,且可以remove
0 0