1

If I iterate over a map in freemarker twice as below

<#list node_map?keys as node>
  <th>${node}</th>
</#list>
<#list node_map?keys as node>
  <th>${node}</th>
</#list>

Is the order of the keys guaranteed to be same in both iterations? This documentation says that the order of the keys is arbitrary. Does this mean it can change when we iterate over the same map multiple times? It also says that

some hashes maintain a meaningful order

What does this mean?

I am using java Map/HashMap to populate the node_map template variable.

ishan3243
  • 1,870
  • 4
  • 30
  • 49

2 Answers2

1

As far as HashMap.keys() called twice returns the keys in the same order (and it does in all versions of Java so far), the two #list-s will print the keys in the same order (assuming that the set of keys in the backing Map wasn't changed between the two). The documentation just means that some Map-s, in particular HashMap, have a key order that's random as far the (average) user is concerned.

Some details: #list and ?keys are straightforward, they don't mess with ordering, they just call the appropriate TemplateModel methods to list the keys. The ObjectWrapper is the trickier one; this is what wraps Map-s into TemplateModel-s. Legacy configurations use SimpleHash to wrap Map-s, which is known to change key order in some cases compared to the original Map, but only when it's created, not when it's later read. SimpleHash copies the original Map into an internal Map, and in case the original was a HashMap, it copies it into another HashMap, so the behavior will be similar (though the actual key order will be possibly different). More modern configurations use DefaultMapAdapter, which doesn't change the key order of the wrapped Map, as it's just an adapter. So in that case, as far as the wrapped Map always returns the keys in the same order, FreeMarker does too.

ddekany
  • 29,656
  • 4
  • 57
  • 64
1

From the HashMap documentation:

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.

In theory this means that there are absolutely no guarantees about the order of the keys between subsequent iterations even if you do them immediatly one after the other(the time has changed), you can also see this question.

In practice and after checking Java 8 source code HashMap internally has a Node<K,V>[] table array and all it does during iteration is going over it. So if you will do 2 subsequent invocations of node_map?keys without any changes to the map, I can say with confidence that it will be in the same order. I will never actually write code that depends on it though because it's not guaranteed by the contract.

some hashes maintain a meaningful order

This means that you can use other Map implementations that do guarantee consistent ordering for example TreeMap or LinkedHashMap. If you populate node_map with LinkedHashMap then it will be guaranteed to be consistent not only in practice but also in theory(this is what you should do if you want to rely on it).

Oleg
  • 6,124
  • 2
  • 23
  • 40
  • does FreeMarker honor the particular implementation of java.util.Map (such as HashMap, TreeMap etc.) that we use to populate a template variable? Does it use regular java API to access the keys in the map? – ishan3243 Aug 21 '17 at 17:11
  • 1
    @ishan3243 If you use configuration with version `freemarker.template.Configuration.VERSION_2_3_22` or higher then as explained by \@ddekany it uses an adapter that simply calls the methods of the `Map` implementation you passed to it. – Oleg Aug 21 '17 at 23:19