Search code examples
javacollectionsapache-commons-collection

How to use OrderedMapIterator.previous()


Using Apache Commons Collections I found the OrderedMapIterator interface to navigate back and forth in OrderedMap. Iterating to the next entry works as expected. Going to the previous element doesn't return the previous element but the current element instead.

OrderedMap<String, String> linkedMap = new LinkedMap<>();
linkedMap.put("key 1", "value 1");
linkedMap.put("key 2", "value 2");
linkedMap.put("key 3", "value 3");

OrderedMapIterator<String, String> iterator = linkedMap.mapIterator();
while (iterator.hasNext()) {
    String key = iterator.next();
    System.out.println(key);

    if (key.endsWith("2") && iterator.hasPrevious()) {
        System.out.println("previous: " + iterator.previous());
        iterator.next(); // back to current element
    }
}

I expected the output

key 1
key 2
previous: key 1
key 3

but got

key 1
key 2
previous: key 2
key 3

Do I use OrderedMapIterator wrong or is this a bug?


Solution

  • Its because technically .previous() does not exactly set current entry to previous, but to next.before. Look how iteration process works:

    nextEntry() {
        ...
        last = next; //its current
        next = next.after;
        ...
    
    previousEntry() {
        ...
        final LinkEntry<K, V> previous = next.before;
        ...
        next = previous;
        last = previous;
    

    So your flow will affect the last(current)|next states as follows:

    null|1 -> (next) -> 1|2 -> (next) -> 2|3 <- (previous?) <- 2|2 -> (next) -> 3|null
    

    The reason i may think why is behaves so, because its intended to call .next(), .previous() in separate loops.

    Imagine a situation where you iterate all way forward, and then need to iterate all way back.

    while (it.hasNext()) {
        String key = it.next();
        list.add(key);
    }
    while (it.hasPrevious()) {
        String key = it.previous();
        list.remove(key);
    }
    

    With the behaviour which you want to have, you would ended up with [key 3] in list, which is not correct, but currently it works fine.