5

Is there a Map in Java or 3rd-party libraries preserving insertion order (similar to LinkedHashMap) which would also check order of keys during comparison (equals() and hashCode() methods) ? So that Map(a => 1, b => 2) would be different from Map(b => 2, a => 1).

Similar to below but I don't want to reinvent and maintain the wheel:

public class EqualityStrictLinkedMap<K, V> extends ForwardingMap<K, V>
{
    ...

    @Override
    public boolean equals(Object o)
    {
        if (!(o instanceof Map))
            return false;
        Map<K, V> that = (Map<K, V>) o;
        return Iterables.elementsEqual(entrySet(), that.entrySet());
    }

    @Override
    public int hashCode()
    {
        int h = 1;
        for (Map.Entry<K, V> entry: entrySet()) {
            h = (h*31 + Objects.hashCode(entry.getKey()))*31 + Objects.hashCode(entry.getValue());
        }
        return h;
    }
}
Zbynek Vyskovsky - kvr000
  • 18,186
  • 3
  • 35
  • 43
  • 6
    The `Map` interface specifies that equals and hashCode _must_ ignore order. If you don't want to ignore order, you can't implement the `Map` interface. (You could have an `asMap()` view, of course.) There is certainly nothing in Guava or the JDK, and nothing in any library I've ever seen, that will do this for you. – Louis Wasserman Mar 03 '20 at 02:03
  • @LouisWasserman (A) Can you cite the part of the documentation that talks about `equals` and `hashCode` ignoring order? I am reading the Javadoc for [`Map`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Map.html) in Java 11. I do not see any such section, but I may be misunderstanding. (B) Looks like you should make an Answer of your Comment so this Question can be closed. – Basil Bourque Mar 03 '20 at 02:24
  • 2
    I believe it is in reference to [this](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#equals-java.lang.Object-) which states that two `Map`s are equal if their entry-sets are equal, alongside [this](https://docs.oracle.com/javase/8/docs/api/java/util/Set.html#equals-java.lang.Object-) which declares two sets are equal if they have the same size and contain the same elements. – BeUndead Mar 03 '20 at 02:27
  • Note (regardless of if the above is true): nothing is stopping you implementing the `Map` interface, but instead adding some `isEqualsIncludingOrder` type method _as well_. – BeUndead Mar 03 '20 at 02:30
  • That could work, @BeUndead though I want to use it as a key, so overriding `equals` directly makes more sense. Wrapping into another object and calling specific method would help but adds unnecessary complexity. Anyway, thanks for suggestions, I'm a bit surprised that nobody has created that yet. I think the contract (which is not so crystal clear anyway), can be relaxed if it serves specific purpose though obviously drawback would be inconsistent matching with other Map implementations. There are other cases when other data structures behave not consistently with original contract. – Zbynek Vyskovsky - kvr000 Mar 03 '20 at 04:59
  • Are you planning to keep it _immutable_ once you've put it as the `key` (in a `Map`)? Otherwise, changing `hashCode` of something you've put into a `Map` can cause some unexpected behaviour. – BeUndead Mar 03 '20 at 10:56
  • Sure, @BeUndead , that applies to any object which once it's put as a key, nothing specific to this map. – Zbynek Vyskovsky - kvr000 Mar 03 '20 at 14:49

0 Answers0