Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8244572

AbstractMap, HashMap, TreeMap, and unmodifiable Maps' equals() methods operate in the wrong direction

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • 8
    • core-libs
    • None

      AbstractMap.equals() is implemented incorrectly, which can lead to incorrect results if called on a Map with a different membership contract. Since HashMap, TreeMap, and the unmodifiable maps from Map.of et. al. inherit AbstractMap.equals, they all have this problem too.

      Example:

      var umap = Map.of("a", 0, "A", 0);
      var hash = new HashMap<>(umap)
      var tree = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER)
      tree.put("a", 0);
      tree.put("x", 0);

      We now have:

      umap ==> {a=0, A=0}
      hash ==> {a=0, A=0}
      tree ==> {a=0, x=0}

      However:

      hash.equals(tree)
      ==> true *** !!! ***
      tree.equals(hash)
      ==> false *** !!! ***
      hash.entrySet().equals(tree.entrySet())
      ==> false
      tree.entrySet().equals(hash.entrySet())
      ==> true

      Also:

      umap.equals(tree)
      ==> true *** !!! ***
      tree.equals(umap)
      ==> false *** !!! ***
      umap.entrySet().equals(tree.entrySet())
      ==> false
      tree.entrySet().equals(umap.entrySet())
      ==> true

      Results above marked with *** !!! *** are incorrect. The 'true' results not so marked are surprising but correct.

      (ConcurrentHashMap does not have this problem, because it uses a different algorithm for equals(). This is possibly in order to accommodate the case where there are more than Integer.MAX_VALUE mappings. At such sizes, the size() method is clamped at MAX_VALUE and is thus unreliable.)

            smarks Stuart Marks
            smarks Stuart Marks
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: