迭代相同的 HashMap 键两次。订单保证相同吗?
Iterating over the same HashMap keys twice. Is the order guaranteed to be same?
如果我在 freemarker 中迭代地图两次,如下所示
<#list node_map?keys as node>
<th>${node}</th>
</#list>
<#list node_map?keys as node>
<th>${node}</th>
</#list>
是否保证两次迭代中键的顺序相同?这个 documentation 表示按键的顺序是任意的。这是否意味着当我们多次迭代同一张地图时它会发生变化?它还说
some hashes maintain a meaningful order
这是什么意思?
我正在使用 java Map/HashMap
来填充 node_map 模板变量。
至于 HashMap.keys()
以相同的顺序调用两次 returns 键(目前在所有版本的 Java 中都是如此),两个 #list
-s 将以相同的顺序打印密钥(假设支持 Map
中的密钥集在两者之间没有改变)。该文档仅表示某些 Map
-s,特别是 HashMap
,具有随机的键顺序,就(普通)用户而言。
一些细节:#list
和 ?keys
很简单,它们不打乱顺序,它们只是调用适当的 TemplateModel
方法来列出键。 ObjectWrapper
比较棘手;这就是将 Map
-s 包装成 TemplateModel
-s 的原因。遗留配置使用 SimpleHash
来包装 Map
-s,众所周知,与原始 Map
相比,它在某些情况下会更改键顺序,但仅在创建时才会更改,稍后读取时不会更改。 SimpleHash
将原始 Map
复制到内部 Map
,如果原始是 HashMap
,它会将其复制到另一个 HashMap
,因此行为将相似(尽管实际的键顺序可能不同)。更现代的配置使用 DefaultMapAdapter
,它不会更改包装的 Map
的键顺序,因为它只是一个适配器。所以在那种情况下,就包装 Map
总是 returns 相同顺序的键而言,FreeMarker 也是如此。
来自 HashMap 文档:
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
理论上这意味着在后续迭代之间绝对不能保证键的顺序,即使你立即一个接一个地做(时间已经改变),你也可以看到this question .
在实践中,在检查 Java 8 源代码后 HashMap
内部有一个 Node<K,V>[] table
数组,它在迭代期间所做的一切就是遍历它。因此,如果您将在不对地图进行任何更改的情况下对 node_map?keys
进行 2 次后续调用,我可以自信地说它会以相同的顺序进行。我永远不会真正编写依赖于它的代码,因为它不受合同保证。
some hashes maintain a meaningful order
这意味着您可以使用其他 Map
保证一致排序的实现,例如 TreeMap
或 LinkedHashMap
。如果你用LinkedHashMap
填充node_map
那么它不仅在实践上而且在理论上都将保证一致(如果你想依赖它,你应该这样做)。
如果我在 freemarker 中迭代地图两次,如下所示
<#list node_map?keys as node>
<th>${node}</th>
</#list>
<#list node_map?keys as node>
<th>${node}</th>
</#list>
是否保证两次迭代中键的顺序相同?这个 documentation 表示按键的顺序是任意的。这是否意味着当我们多次迭代同一张地图时它会发生变化?它还说
some hashes maintain a meaningful order
这是什么意思?
我正在使用 java Map/HashMap
来填充 node_map 模板变量。
至于 HashMap.keys()
以相同的顺序调用两次 returns 键(目前在所有版本的 Java 中都是如此),两个 #list
-s 将以相同的顺序打印密钥(假设支持 Map
中的密钥集在两者之间没有改变)。该文档仅表示某些 Map
-s,特别是 HashMap
,具有随机的键顺序,就(普通)用户而言。
一些细节:#list
和 ?keys
很简单,它们不打乱顺序,它们只是调用适当的 TemplateModel
方法来列出键。 ObjectWrapper
比较棘手;这就是将 Map
-s 包装成 TemplateModel
-s 的原因。遗留配置使用 SimpleHash
来包装 Map
-s,众所周知,与原始 Map
相比,它在某些情况下会更改键顺序,但仅在创建时才会更改,稍后读取时不会更改。 SimpleHash
将原始 Map
复制到内部 Map
,如果原始是 HashMap
,它会将其复制到另一个 HashMap
,因此行为将相似(尽管实际的键顺序可能不同)。更现代的配置使用 DefaultMapAdapter
,它不会更改包装的 Map
的键顺序,因为它只是一个适配器。所以在那种情况下,就包装 Map
总是 returns 相同顺序的键而言,FreeMarker 也是如此。
来自 HashMap 文档:
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
理论上这意味着在后续迭代之间绝对不能保证键的顺序,即使你立即一个接一个地做(时间已经改变),你也可以看到this question .
在实践中,在检查 Java 8 源代码后 HashMap
内部有一个 Node<K,V>[] table
数组,它在迭代期间所做的一切就是遍历它。因此,如果您将在不对地图进行任何更改的情况下对 node_map?keys
进行 2 次后续调用,我可以自信地说它会以相同的顺序进行。我永远不会真正编写依赖于它的代码,因为它不受合同保证。
some hashes maintain a meaningful order
这意味着您可以使用其他 Map
保证一致排序的实现,例如 TreeMap
或 LinkedHashMap
。如果你用LinkedHashMap
填充node_map
那么它不仅在实践上而且在理论上都将保证一致(如果你想依赖它,你应该这样做)。