Comparing two maps

后端 未结 2 876
萌比男神i
萌比男神i 2020-12-02 15:32

I have two maps declared as Map. The Object here could be another Map (and so on). I want

2条回答
  •  一向
    一向 (楼主)
    2020-12-02 15:52

    Quick Answer

    You should use the equals method since this is implemented to perform the comparison you want. toString() itself uses an iterator just like equals but it is a more inefficient approach. Additionally, as @Teepeemm pointed out, toString is affected by order of elements (basically iterator return order) hence is not guaranteed to provide the same output for 2 different maps (especially if we compare two different maps).

    Note/Warning: Your question and my answer assume that classes implementing the map interface respect expected toString and equals behavior. The default java classes do so, but a custom map class needs to be examined to verify expected behavior.

    See: http://docs.oracle.com/javase/7/docs/api/java/util/Map.html

    boolean equals(Object o)
    

    Compares the specified object with this map for equality. Returns true if the given object is also a map and the two maps represent the same mappings. More formally, two maps m1 and m2 represent the same mappings if m1.entrySet().equals(m2.entrySet()). This ensures that the equals method works properly across different implementations of the Map interface.

    Implementation in Java Source (java.util.AbstractMap)

    Additionally, java itself takes care of iterating through all elements and making the comparison so you don't have to. Have a look at the implementation of AbstractMap which is used by classes such as HashMap:

     // Comparison and hashing
    
        /**
         * Compares the specified object with this map for equality.  Returns
         * true if the given object is also a map and the two maps
         * represent the same mappings.  More formally, two maps m1 and
         * m2 represent the same mappings if
         * m1.entrySet().equals(m2.entrySet()).  This ensures that the
         * equals method works properly across different implementations
         * of the Map interface.
         *
         * 

    This implementation first checks if the specified object is this map; * if so it returns true. Then, it checks if the specified * object is a map whose size is identical to the size of this map; if * not, it returns false. If so, it iterates over this map's * entrySet collection, and checks that the specified map * contains each mapping that this map contains. If the specified map * fails to contain such a mapping, false is returned. If the * iteration completes, true is returned. * * @param o object to be compared for equality with this map * @return true if the specified object is equal to this map */ public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map m = (Map) o; if (m.size() != size()) return false; try { Iterator> i = entrySet().iterator(); while (i.hasNext()) { Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(m.get(key)==null && m.containsKey(key))) return false; } else { if (!value.equals(m.get(key))) return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; }

    Comparing two different types of Maps

    toString fails miserably when comparing a TreeMap and HashMap though equals does compare contents correctly.

    Code:

    public static void main(String args[]) {
    HashMap map = new HashMap();
    map.put("2", "whatever2");
    map.put("1", "whatever1");
    TreeMap map2 = new TreeMap();
    map2.put("2", "whatever2");
    map2.put("1", "whatever1");
    
    System.out.println("Are maps equal (using equals):" + map.equals(map2));
    System.out.println("Are maps equal (using toString().equals()):"
            + map.toString().equals(map2.toString()));
    
    System.out.println("Map1:"+map.toString());
    System.out.println("Map2:"+map2.toString());
    }
    

    Output:

    Are maps equal (using equals):true
    Are maps equal (using toString().equals()):false
    Map1:{2=whatever2, 1=whatever1}
    Map2:{1=whatever1, 2=whatever2}
    

提交回复
热议问题