如何在Java中检查LinkedHashMaps的相等性 - 还考虑了插入顺序?

时间:2016-04-29 14:58:44

标签: java equals linkedhashmap

我想检查Java中两个LinkedHashMaps的相等性。

equals() - 方法位于AbstractMap,仅检查比较列表中是否存在具有相同键和值的条目。因此,不检查插入顺序:

package com.stackoverflow.tests;

import java.util.LinkedHashMap;

public class LinkedHashMapEqualsTest {

  public static void main(String[] args) {
    LinkedHashMap<String, String> lhm1 = new LinkedHashMap<String, String>();
    lhm1.put("A", "1");
    lhm1.put("B", "2");
    lhm1.put("C", "3");
    LinkedHashMap<String, String> lhm2 = new LinkedHashMap<String, String>();
    lhm2.put("A", "1");
    lhm2.put("B", "2");
    lhm2.put("C", "3");
    LinkedHashMap<String, String> lhm3 = new LinkedHashMap<String, String>();
    lhm3.put("A", "1");
    lhm3.put("C", "3");
    lhm3.put("B", "2");
    LinkedHashMap<String, String> lhm4 = new LinkedHashMap<String, String>();
    lhm4.put("A", "1");
    lhm4.put("B", "2");
    LinkedHashMap<String, String> lhm5 = new LinkedHashMap<String, String>();
    lhm5.put("A", "2");
    lhm5.put("B", "2");
    lhm5.put("C", "3");

    if(lhm1.equals(lhm1)) {
      System.out.println("Positive control. - SUCCESS");
    }
    if(lhm1.equals(lhm2)) {
      System.out.println("lhm1 does equal lhm2; as expected. - SUCCESS");
    }
    if(lhm1.equals(lhm3)) {
      System.out.println("lhm1 does equal lhm3, although the insert-order is different.");
    }
    if(!lhm1.equals(lhm4)) {
      System.out.println("Negative control 1. - SUCCESS");
    }
    if(!lhm1.equals(lhm5)) {
      System.out.println("Negative control 2. - SUCCESS");
    }

  }

}

如何检查两个比较列表的插入顺序是否相同?

2 个答案:

答案 0 :(得分:6)

我可能无法覆盖equals()的{​​{1}},但提供帮助方法,例如像这样(灵感来自LinkedHashMap):

AbstractList#equals(...)

然后你就像public static <K, V> boolean linkedEquals( LinkedHashMap<K, V> left, LinkedHashMap<K, V> right) { Iterator<Entry<K, V>> leftItr = left.entrySet().iterator(); Iterator<Entry<K, V>> rightItr = right.entrySet().iterator(); while ( leftItr.hasNext() && rightItr.hasNext()) { Entry<K, V> leftEntry = leftItr.next(); Entry<K, V> rightEntry = rightItr.next(); //AbstractList does null checks here but for maps we can assume you never get null entries if (! leftEntry.equals(rightEntry)) return false; } return !(leftItr.hasNext() || rightItr.hasNext()); } 一样使用它。

修改

根据请求,产生较低性能(由于多次不必要的迭代)但需要编写较少代码的另一种方法是将条目集转换为列表并比较那些,例如:像这样:

if( linkedEquals(lhm1, lhm3) )

答案 1 :(得分:1)

在没有任何扩展的情况下执行此操作的一种天真方式是使用toString()输出:

public static <K,V> boolean equalConsideringInsertionOrder(
  Map<K,V> left, Map<K,V> right){

  return left.toString().equals(right.toString());
}

但正如评论中指出的那样,这个版本有些不确定。 toString()不是规范格式,因此不应该以这种方式使用。

更精细,高效和正确的版本将是这样的:

public static <K, V> boolean equalConsideringInsertionOrder(
        Map<K, V> left, Map<K, V> right) {

    Iterator<Map.Entry<K, V>> leftIterator = left.entrySet().iterator();
    Iterator<Map.Entry<K, V>> rightIterator = right.entrySet().iterator();
    while (leftIterator.hasNext() && rightIterator.hasNext()) {
        Map.Entry<K, V> leftEntry = leftIterator.next();
        Map.Entry<K, V> rightEntry = rightIterator.next();
        if (!Objects.equals(leftEntry.getKey(), rightEntry.getKey())
                || !Objects.equals(leftEntry.getValue(),rightEntry.getValue())) {
            return false;
        }
    }
    return !leftIterator.hasNext() && !rightIterator.hasNext();
}