7

LinkedHashMap description says "it maintains a doubly-linked list running through all of its entries" so I'm wondering how to get the last entry or key entered? Can I confidently downcast .values() to LinkedList to get that doubly-linked list and use .getLast() of that? Or is it an instance of some other Java collection?

I want to stick with java.util if possible.

Navigateur
  • 1,852
  • 3
  • 23
  • 39
  • 1
    The method `values()` does not return a `List<>` view or a `LinkedList<>` view; rather it returns a `Collection<>` view. The actual type returned is an instance of a private class called `Values` that extends `AbstractCollection<>`. – Swaranga Sarma Sep 03 '11 at 12:01
  • 1
    You could make a custom class that will store the last element entered... –  Sep 03 '11 at 13:03
  • bdares, would you like to put this comment as an answer? It's my fave and I'll accept it as the answer if you do. – Navigateur Aug 02 '12 at 17:02
  • Seems impossible with java.util (without reflection) but see http://stackoverflow.com/a/1936472/32453 – rogerdpack Dec 09 '15 at 16:52

4 Answers4

1

Yes, you can get the last element. But you'll have to look at the suggestions from others to get the last element of the Collection<V> returned by values().

I checked in the source code that the returned values are indeed in the expected order: The AbstactCollection<V> returned by LinkedListMap.values() is backed by an Iterator<V> over the values which is itself directly linked to the Iterator<K> over the keys. And obviously the Iterator<K> over the keys is implemented with the ordered doubly linked list.

toto2
  • 5,306
  • 21
  • 24
  • It's worth pointing out that nothing in the documentation suggests iteration over a LinkedHashMap's values are guaranteed to respect the insertion order of the map. – Max Feb 24 '14 at 17:25
0

I have "extended" the Jdk LinkedHashMap to allow that, you can take a look at: LinkedHashMapEx.java

user2179737
  • 493
  • 3
  • 6
0

No, sorry, you cannot.

The "maintained doubly-linked list" is not any java.util.LinkedList type or other collection. It's manually implemented in LinkedHashMap and LinkedHashMap.Entry classes.

You can only build LinkedList from values() and then use letLast() :

Foo last = new LinkedList<Foo>(myLinkedHashMap.values()).getLast();
Michał Šrajer
  • 30,364
  • 7
  • 62
  • 85
0

Update: My previous answer was wrong. You cannot do it without modifying the default behaviour! See below why.


..how to get the last entry or key entered?

From the API description of LinkedHashMap you can read:

A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order. In insertion-ordered linked hash maps, merely changing the value associated with a key that is already contained in the map is not a structural modification. In access-ordered linked hash maps, merely querying the map with get is a structural modification.

So what does it all mean?

  • access-ordered - every time you do a put or a get the order of the elements changes
  • insertion-ordered - when inserting elements (for the first time) they are added last

For example:

map.put(1, 1); 
map.put(2, 2); 
map.put(1, 10);
System.out.println(map);

... will print {1=10, 2=2} with insertion-ordered and {2=2, 1=10} with *access-ordered'. The trouble is using access-ordered if of course if you do a get operations the order also changes.


How to fix

So... how to fix. Well the LinkedHashMap cannot be used directly used. So you can wrap it (do not care about the corny name) and override the put and the putAll methods so that they remove the key from the map first before putting it back in!

class BestLinkedHashMap<K, V> extends LinkedHashMap<K, V> {

    @Override
    public V put(K key, V value) {
        V last = super.remove(key);
        super.put(key, value);
        return last;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        for (K key : m.keySet())
            super.remove(key);

        super.putAll(m);
    }
}

Then to get the last element, either do:

  • wrap the output from in a LinkedList implementation:

    V v = new LinkedList<V>(map.values()).getLast();
    
  • toArray() way:

    Collection<V> values = map.values();
    V v = values.toArray(new V[0])[values.size() - 1];
    
  • iterate to the last element using the iterator:

    Iterator<V> it = values.iterator();
    V last = null;
    while (it.hasNext())
        last = it.next();
    
dacwe
  • 43,066
  • 12
  • 116
  • 140