Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Properties.propertyNames() returns Enumeration in reverse order - why?

In my project I am using some Properties file. I have noticed strange behaviour of Properties.propertyNames(), it returns an Enumeration, that Enumeration is in reverse order. I did a test: The file content is:

TT.1=Development
TT.2=Application Setup / Release
TT.3=Project Management
TT.4=Meetings and Discussions

The code is:

    Enumeration<?> enumeration = properties.propertyNames();
    while (enumeration.hasMoreElements()) {
        String key = (String) enumeration.nextElement();
        String value = properties.getProperty(key);
        System.out.println(key + " " + value);                        
    }

The output is:

TT.4 Application Setup / Release
TT.3 Development
TT.2 Meetings and Discussions
TT.1 Project Management

Can anyone tell what is the reason behind? Thank you.
Edit: As the Key of the HashTable is of the form TT.X where X is a number I sorted it to make the right order. Here is the next implementation:

    this.taskTypeList = new ArrayList<String>(0); 
    Map<String, String> reverseTaskMap = new HashMap<String, String>(0);        
    Properties properties = loadTaskProperty();
    Enumeration<?> enumeration = properties.propertyNames();
    while (enumeration.hasMoreElements()) {
        String key = (String) enumeration.nextElement();
        String value = properties.getProperty(key);
        reverseTaskMap.put(key, value);            
    }

    LinkedList<Map.Entry<String, String>> linkedList = new LinkedList<Map.Entry<String, String>>(reverseTaskMap.entrySet());
    Collections.sort(linkedList, new Comparator<Map.Entry<String, String>>() {
        public int compare(Entry<String, String> object1, Entry<String, String> object2) {                            
            return Integer.valueOf(Integer.parseInt(object1.getKey().split("\\.")[1])).compareTo(Integer.valueOf(Integer.parseInt(object2.getKey().split("\\.")[1])));
        }
    });

    for (Iterator<Map.Entry<String, String>> iterator = linkedList.iterator(); iterator.hasNext(); ) {
        Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
        taskTypeList.add(entry.getValue());
    }
like image 840
Tapas Bose Avatar asked Dec 01 '22 03:12

Tapas Bose


2 Answers

It's a coincidence. Properties doesn't guarantee any particular order of elements, so the order can be arbitrary.

More specifically, the following implementation details lead to this behaviour:

  • Since your keys differ only in the last letter, their hashcodes (produced by String.hashCode()) differ only in the last several bits.

  • Properties is a subclass of Hashtable. Unlike HashMap, HashTable doesn't apply a supplemental hash function to mix bits of hashcode. Since Hashtable uses the last bits of hashcode as a number of hash bucket to place the elements, your elements are placed into the consequent buckets. It's a really interesting point - it means that this implementation of Hashtable can show a worst case performance in some real-world scenarios, whereas for HashMap it's unlikely. Yet another reason to favor HashMap over Hashtable.

  • For some reason Hashtable's Enumeration traverses buckets in reverse order, thus added elements are returned in reverse order.

like image 177
axtavt Avatar answered Dec 05 '22 10:12

axtavt


It's just a coincidence; the properties are actually returned in an undefined order. "Properties" is just a Hashtable; Hashtable enumerations do not return their keys in any particular order.

like image 20
Ernest Friedman-Hill Avatar answered Dec 05 '22 10:12

Ernest Friedman-Hill