如何有效地迭代 Java Map 中的每个条目?
如果我有一个在 Java 中实现 Map 接口的对象,并且我希望迭代其中包含的每一对,那么遍历映射的最有效方法是什么?
元素的顺序是否取决于接口的特定映射实现?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
如果我有一个在 Java 中实现 Map 接口的对象,并且我希望迭代其中包含的每一对,那么遍历映射的最有效方法是什么?
元素的顺序是否取决于接口的特定映射实现?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(30)
Java 8
我们有
forEach
方法,它接受 lambda 表达式。 我们还有 stream蜜蜂。 考虑一个映射:迭代键:
迭代值:
迭代条目(使用 forEach 和 Streams):
流的优点是它们可以如果我们愿意的话,可以很容易地并行化。 我们只需使用
parallelStream()
代替上面的stream()
即可。forEachOrdered
与带有流的forEach
?forEach
不遵循遇到顺序(如果已定义),并且本质上是不确定的,而forEachOrdered
则不然。 所以forEach
不保证顺序会被保留。 另请查看此了解更多信息。Java 8
We have got
forEach
method that accepts a lambda expression. We have also got stream APIs. Consider a map:Iterate over keys:
Iterate over values:
Iterate over entries (Using forEach and Streams):
The advantage with streams is they can be parallelized easily in case we want to. We simply need to use
parallelStream()
in place ofstream()
above.forEachOrdered
vsforEach
with streams ?The
forEach
does not follow encounter order (if defined) and is inherently non-deterministic in nature where as theforEachOrdered
does. SoforEach
does not guarantee that the order would be kept. Also check this for more.您可以使用泛型来做到这一点:
You can do it using generics:
使用Java 8:
Use Java 8:
对 Map 的有效迭代解决方案是从 Java 5 到 Java 7 的
for
循环。如下所示:从 Java 8 开始,您可以使用 lambda 表达式对 Map 进行迭代。 它是一个增强的
forEach
如果你想为 lambda 编写一个条件,你可以这样写:
An effective iterative solution over a Map is a
for
loop from Java 5 through Java 7. Here it is:From Java 8, you can use a lambda expression to iterate over a Map. It is an enhanced
forEach
If you want to write a conditional for lambda you can write it like this:
是的,顺序取决于具体的 Map 实现。
@ScArcher2 拥有更优雅的 Java 1.5语法。 在 1.4 中,我会做这样的事情:
Yes, the order depends on the specific Map implementation.
@ScArcher2 has the more elegant Java 1.5 syntax. In 1.4, I would do something like this:
在 Java 10+ 上:
On Java 10+:
为了总结其他答案并将它们与我所知道的结合起来,我找到了 10 种主要方法来做到这一点(见下文)。 另外,我编写了一些性能测试(见下面的结果)。 例如,如果我们想求一个map中所有键和值的总和,我们可以这样写:
使用迭代器和Map.Entry
使用foreach和Map.Entry >
使用 Java 8 中的 forEach
使用 keySet 和 foreach
使用keySet和迭代器
使用for和Map.Entry< /p>
使用 Java 8 Stream API
使用 Java 8 Stream API 并行
使用
Apache Collections
的 IterableMap使用 Eclipse (CS) 集合的 MutableMap
性能测试(模式 = AverageTime,系统 = Windows 8.1 64 位、Intel i7-4790 3.60 GHz,16 GB)
对于小地图(100 个元素),得分 0.308 是最佳
对于 10000 个元素的地图,分数 37.606 是最佳
对于具有 100000 个元素的地图,分数 1184.767 是最佳
图(性能测试取决于地图大小)
表(性能测试取决于地图大小)
所有测试均在 < a href="https://github.com/Vedenin/useful-java-links/blob/master/helloworlds/5.0-other-examples/src/main/java/other_examples/IterateThroughHashMapTest.java" rel="noreferrer"> GitHub。
To summarize the other answers and combine them with what I know, I found 10 main ways to do this (see below). Also, I wrote some performance tests (see results below). For example, if we want to find the sum of all of the keys and values of a map, we can write:
Using iterator and Map.Entry
Using foreach and Map.Entry
Using forEach from Java 8
Using keySet and foreach
Using keySet and iterator
Using for and Map.Entry
Using the Java 8 Stream API
Using the Java 8 Stream API parallel
Using IterableMap of
Apache Collections
Using MutableMap of Eclipse (CS) collections
Perfomance tests (mode = AverageTime, system = Windows 8.1 64-bit, Intel i7-4790 3.60 GHz, 16 GB)
For a small map (100 elements), score 0.308 is the best
For a map with 10000 elements, score 37.606 is the best
For a map with 100000 elements, score 1184.767 is the best
Graphs (performance tests depending on map size)
Table (perfomance tests depending on map size)
All tests are on GitHub.
在 Java 8 中,您可以使用新的 lambda 功能干净、快速地完成此操作:
k
和v
的类型将由编译器推断,无需使用 <不再是代码>Map.Entry了。十分简单!
In Java 8 you can do it clean and fast using the new lambdas features:
The type of
k
andv
will be inferred by the compiler and there is no need to useMap.Entry
anymore.Easy-peasy!
使用Java 8,您可以使用 forEach 和 lambda 表达式迭代 Map,
With Java 8, you can iterate Map using forEach and lambda expression,
对于 Eclipse Collections,您可以在
forEachKeyValue
方法中使用 < a href="https://github.com/eclipse/eclipse-collections/blob/master/eclipse-collections-api/src/main/java/org/eclipse/collections/api/map/MapIterable.java" rel= "nofollow noreferrer">MapIterable
接口,由MutableMap
和ImmutableMap
接口及其实现继承。将
forEachKeyValue
与 Eclipse Collections (EC)Map
实现结合使用比使用entrySet
更高效的原因是 ECMap
> 实现不存储Map.Entry
对象。 将entrySet
与 ECMap
实现结合使用会导致动态生成Map.Entry
对象。forEachKeyValue
方法能够避免创建Map.Entry
对象,因为它可以直接导航Map
实现的内部结构。 在这种情况下,使用内部迭代器比使用外部迭代器更有好处。注意:我是 Eclipse Collections 的提交者。
With Eclipse Collections, you would use the
forEachKeyValue
method on theMapIterable
interface, which is inherited by theMutableMap
andImmutableMap
interfaces and their implementations.The reason using
forEachKeyValue
with Eclipse Collections (EC)Map
implementations will be more efficient than usingentrySet
is because ECMap
implementations do not storeMap.Entry
objects. UsingentrySet
with ECMap
implementations results inMap.Entry
objects being generated dynamically. TheforEachKeyValue
method is able to avoid creating theMap.Entry
objects because it can navigate the internal structure of theMap
implementations directly. This is a case where there is a benefit of using an internal iterator over an external iterator.Note: I am a committer for Eclipse Collections.
正确的方法是使用已接受的答案,因为它是最有效的。 我发现下面的代码看起来更干净一些。
The correct way to do this is to use the accepted answer as it is the most efficient. I find the following code looks a bit cleaner.
仅供参考,如果您只对地图的键/值而不是其他感兴趣,您也可以使用
map.keySet()
和map.values()
。FYI, you can also use
map.keySet()
andmap.values()
if you're only interested in keys/values of the map and not the other.这是一个由两部分组成的问题:
如何迭代 Map 的条目 - @ScArcher2 已回答 完美。
迭代的顺序是什么 - 如果您只使用
Map
,那么严格来说,没有顺序保证。 因此,您不应该真正依赖任何实现给出的顺序。 但是,SortedMap
接口扩展了Map
并提供了您正在寻找的内容 - 实现将给出一致的排序顺序。NavigableMap
是另一个有用的扩展 - 这是一个SortedMap
,具有用于按键集中的有序位置查找条目的附加方法。 因此,这可能可以消除首先进行迭代的需要 - 您可能能够在使用higherEntry
、lowerEntry
后找到您所在的特定条目
code>、ceilingEntry
或floorEntry
方法。descendingMap
方法甚至为您提供了反转遍历顺序的显式方法。This is a two part question:
How to iterate over the entries of a Map - @ScArcher2 has answered that perfectly.
What is the order of iteration - if you are just using
Map
, then strictly speaking, there are no ordering guarantees. So you shouldn't really rely on the ordering given by any implementation. However, theSortedMap
interface extendsMap
and provides exactly what you are looking for - implementations will aways give a consistent sort order.NavigableMap
is another useful extension - this is aSortedMap
with additional methods for finding entries by their ordered position in the key set. So potentially this can remove the need for iterating in the first place - you might be able to find the specificentry
you are after using thehigherEntry
,lowerEntry
,ceilingEntry
, orfloorEntry
methods. ThedescendingMap
method even gives you an explicit method of reversing the traversal order.使用迭代器和泛型的示例:
Example of using iterator and generics:
迭代映射的典型代码是:
HashMap
是规范的映射实现,并且不做出保证(或者如果没有对其执行变异操作,则它不应该更改顺序)。SortedMap
将根据键的自然顺序返回条目,或者返回一个Comparator
(如果提供)。 LinkedHashMap 将按照插入顺序或访问顺序返回条目,具体取决于它的构造方式。EnumMap
按键的自然顺序返回条目。(更新:我认为这不再是正确的。)注意,
实例! 然而,每次新的迭代器前进时,
IdentityHashMap
entrySet
迭代器当前有一个特殊的实现,它返回相同的entrySet
中每个项目的 Map.EntryMap.Entry
都会更新。Typical code for iterating over a map is:
HashMap
is the canonical map implementation and doesn't make guarantees (or though it should not change the order if no mutating operations are performed on it).SortedMap
will return entries based on the natural ordering of the keys, or aComparator
, if provided.LinkedHashMap
will either return entries in insertion-order or access-order depending upon how it has been constructed.EnumMap
returns entries in the natural order of keys.(Update: I think this is no longer true.) Note,
IdentityHashMap
entrySet
iterator currently has a peculiar implementation which returns the sameMap.Entry
instance for every item in theentrySet
! However, every time a new iterator advances theMap.Entry
is updated.如果循环键的效率是您的应用的首要任务,那么请选择一个
Map
实现来按您所需的顺序维护键。是的,一点没错。
Map
的不同实现维护键值对的不同顺序。请参阅我创建的表格,该表总结了与 Java 11 捆绑的各种
Map
实现。具体来说,请注意迭代顺序列。 单击/点击进行缩放。您可以看到有四个
Map
实现维持顺序:TreeMap
ConcurrentSkipListMap
LinkedHashMap
EnumMap
NavigableMap
接口其中两个实现了
NavigableMap
接口:TreeMap< /代码> &
ConcurrentSkipListMap
。旧的
SortedMap
接口已被较新的NavigableMap
接口。 但您可能会发现第三方实现仅实现旧接口。自然顺序
如果您想要
Map
保持其对按键的“自然顺序”排列,请使用TreeMap
或ConcurrentSkipListMap
。 术语“自然顺序”意味着键实现的类可比较
。compareTo
方法用于排序时进行比较。自定义顺序
如果要为键指定自定义排序例程以用于维护排序顺序,请传递
Comparator
实现适合您的键的类。 使用TreeMap
或ConcurrentSkipListMap
,传递您的Comparator
。原始插入顺序
如果您希望映射对保持插入映射时的原始顺序,请使用
LinkedHashMap
。枚举定义顺序
如果您使用的是枚举,例如
DayOfWeek
或Month
作为您的键,使用EnumMap
类。 这个类不仅经过高度优化以使用很少的内存并且运行速度非常快,而且它按照枚举定义的顺序维护您的对。 以DayOfWeek
为例,迭代时会先找到DayOfWeek.MONDAY
的key,最后找到DayOfWeek.SUNDAY
的key 。其他注意事项
在选择
Map
实现时,还要考虑:Collections::synchronizedMap
(不太可取)。上面的图表涵盖了这两个注意事项。
If efficiency of looping the keys is a priority for your app, then choose a
Map
implementation that maintains the keys in your desired order.Yes, absolutely.
Map
implementations promise a certain iteration order, others do not.Map
maintain different ordering of the key-value pairs.See this table I created summarizing the various
Map
implementations bundled with Java 11. Specifically, notice the iteration order column. Click/tap to zoom.You can see there are four
Map
implementations maintaining an order:TreeMap
ConcurrentSkipListMap
LinkedHashMap
EnumMap
NavigableMap
interfaceTwo of those implement the
NavigableMap
interface:TreeMap
&ConcurrentSkipListMap
.The older
SortedMap
interface is effectively supplanted by the newerNavigableMap
interface. But you may find 3rd-party implementations implementing the older interface only.Natural order
If you want a
Map
that keeps its pairs arranged by the “natural order” of the key, useTreeMap
orConcurrentSkipListMap
. The term “natural order” means the class of the keys implementsComparable
. The value returned by thecompareTo
method is used for comparison in sorting.Custom order
If you want to specify a custom sorting routine for your keys to be used in maintaining a sorted order, pass a
Comparator
implementation appropriate to the class of your keys. Use eitherTreeMap
orConcurrentSkipListMap
, passing yourComparator
.Original insertion order
If you want the pairs of your map to be kept in their original order in which you inserted them into the map, use
LinkedHashMap
.Enum-definition order
If you are using an enum such as
DayOfWeek
orMonth
as your keys, use theEnumMap
class. Not only is this class highly optimized to use very little memory and run very fast, it maintains your pairs in the order defined by the enum. ForDayOfWeek
, for example, the key ofDayOfWeek.MONDAY
will be first found when iterated, and the key ofDayOfWeek.SUNDAY
will be last.Other considerations
In choosing a
Map
implementation, also consider:Collections::synchronizedMap
(less preferable).Both of these considerations are covered in the graphic table above.
这些都是迭代HashMap的可能方式。
These are all the possible ways of iterating HashMap.
Java 8 最紧凑:
Most compact with Java 8:
理论上,最有效的方法将取决于 Map 的实现。 官方的方法是调用
map.entrySet()
,它返回一组Map.Entry
,其中每个包含一个键和一个值(>entry.getKey()
和entry.getValue()
)。在特殊的实现中,无论您使用
map.keySet()
、map.entrySet()
还是其他东西,可能会有所不同。 但我想不出为什么有人会这样写。 最有可能的是,你所做的事情对性能没有影响。是的,顺序将取决于实现 - 以及(可能)插入顺序和其他难以控制的因素。
[编辑] 我最初编写了
valueSet()
,但当然entrySet()
实际上是答案。In theory, the most efficient way will depend on which implementation of Map. The official way to do this is to call
map.entrySet()
, which returns a set ofMap.Entry
, each of which contains a key and a value (entry.getKey()
andentry.getValue()
).In an idiosyncratic implementation, it might make some difference whether you use
map.keySet()
,map.entrySet()
or something else. But I can't think of a reason why anyone would write it like that. Most likely it makes no difference to performance what you do.And yes, the order will depend on the implementation - as well as (possibly) the order of insertion and other hard-to-control factors.
[edit] I wrote
valueSet()
originally but of courseentrySet()
is actually the answer.排序始终取决于具体的地图实现。
使用 Java 8,您可以使用以下任一方法:
或者:
结果将是相同的(相同的顺序)。 EntrySet 由地图支持,因此您将获得相同的顺序。 第二个很方便,因为它允许您使用 lambda,例如,如果您只想打印大于 5 的 Integer 对象:
下面的代码显示了通过 LinkedHashMap 和普通 HashMap 的迭代(示例)。 您将看到顺序的差异:
输出:
The ordering will always depend on the specific map implementation.
Using Java 8 you can use either of these:
Or:
The result will be the same (same order). The entrySet backed by the map so you are getting the same order. The second one is handy as it allows you to use lambdas, e.g. if you want only to print only Integer objects that are greater than 5:
The code below shows iteration through LinkedHashMap and normal HashMap (example). You will see difference in the order:
Output:
用 Java 1.4 试试这个:
Try this with Java 1.4:
Java 8:
您可以使用 lambda 表达式:
有关详细信息,请遵循 这个。
Java 8:
You can use lambda expressions:
For more information, follow this.
在 Map 中,人们可以对
键
和/或值
和/或两者(例如,entrySet)
进行迭代,具体取决于某人的兴趣_例如:迭代
按键 -> 地图的 keySet()
:迭代
值 -> 地图的values()
:迭代
两者 -> 地图的entrySet()
:此外,有3种不同的方式来迭代HashMap。 它们如下:
In Map one can Iteration over
keys
and/orvalues
and/orboth (e.g., entrySet)
depends on one's interested in_ Like:Iterate through the
keys -> keySet()
of the map:Iterate through the
values -> values()
of the map:Iterate through the
both -> entrySet()
of the map:Moreover, there are 3 different ways to iterate through a HashMap. They are as below:
Lambda 表达式 Java 8
在 Java 1.8 (Java 8) 中,通过使用聚合操作(流操作)中的 forEach 方法,这变得更加容易,该方法看起来类似于Iterable接口中的迭代器。
只需将以下语句复制粘贴到您的代码中,并将 HashMap 变量从 hm 重命名为您的 HashMap 变量即可打印出键值对。
下面是我尝试使用Lambda 表达式的示例代码。 这东西太酷了。 一定要试。
也可以使用 Spliterator 来实现同样的目的。
更新
包括 Oracle 文档的文档链接。
有关 Lambda 的更多信息,请访问此链接< /a> 且必须阅读 聚合操作,对于 Spliterator,请转到此 < a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html" rel="nofollow noreferrer">链接。
Lambda Expression Java 8
In Java 1.8 (Java 8) this has become lot easier by using forEach method from Aggregate operations(Stream operations) that looks similar to iterators from Iterable Interface.
Just copy paste below statement to your code and rename the HashMap variable from hm to your HashMap variable to print out key-value pair.
Below is the sample code that I tried using Lambda Expression. This stuff is so cool. Must try.
Also one can use Spliterator for the same.
UPDATE
Including documentation links to Oracle Docs.
For more on Lambda go to this link and must read Aggregate Operations and for Spliterator go to this link.
是的,正如许多人同意的那样,这是迭代
Map
的最佳方式。但如果地图为
null
,则有可能抛出NullPointerException
。 不要忘记输入null
.check in。Yes, as many people agreed this is the best way to iterate over a
Map
.But there are chances to throw
NullPointerException
if the map isnull
. Don't forget to putnull
.check in.有很多方法可以做到这一点。 下面是几个简单的步骤:
假设您有一个像这样的 Map:
然后您可以执行如下操作来迭代地图元素。
There are a lot of ways to do this. Below is a few simple steps:
Suppose you have one Map like:
Then you can do something like the below to iterate over map elements.
或者
OR
如果您有一个通用的无类型映射,您可以使用:
If you have a generic untyped Map you can use: