如果我在自由标记中迭代地图两次,如下所示
<#list node_map?keys as node>
<th>${node}</th>
</#list>
<#list node_map?keys as node>
<th>${node}</th>
</#list>
两次迭代中键的顺序是否保证相同?本文档指出密钥的顺序是任意的。这是否意味着当我们多次迭代同一地图时,它可以改变?它还说
一些哈希保持有意义的顺序
这是什么意思?
我正在使用javaMap/HashMap
来填充node_map模板变量。
来自 HashMap 文档:
此类不保证映射的顺序;特别是,它不保证顺序在一段时间内保持不变。
从理论上讲,这意味着即使您立即一个接一个地执行密钥(时间已更改(,也绝对无法保证后续迭代之间的键顺序,您也可以看到这个问题。
在实践中,在检查Java 8源代码之后,内部HashMap
有一个Node<K,V>[] table
数组,它在迭代期间所做的只是遍历它。因此,如果您在不对地图进行任何更改的情况下对node_map?keys
进行 2 次后续调用,我可以自信地说它将按相同的顺序进行。我永远不会真正编写依赖于它的代码,因为它不受合同保证。
一些哈希保持有意义的顺序
这意味着您可以使用其他Map
实现来保证一致的排序,例如TreeMap
或LinkedHashMap
。如果你用LinkedHashMap
填充node_map
,那么它不仅在实践中而且在理论上都是一致的(如果你想依赖它,这是你应该做的(。
只要调用两次HashMap.keys()
以相同的顺序返回键(到目前为止,在所有版本的 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
始终以相同的顺序返回密钥,FreeMarker也会这样做。